-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathassertions.go
148 lines (135 loc) · 3.66 KB
/
assertions.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Use and distribution licensed under the Apache license version 2.
//
// See the COPYING file in the root project directory for full text.
package http
import (
nethttp "net/http"
"strings"
gdtjson "github.com/gdt-dev/gdt/assertion/json"
gdttypes "github.com/gdt-dev/gdt/types"
)
// Expect contains one or more assertions about an HTTP response
type Expect struct {
// JSON contains the assertions about JSON data in the response
JSON *gdtjson.Expect `yaml:"json,omitempty"`
// Headers contains a list of HTTP headers that should be in the response
Headers []string `yaml:"headers,omitempty"`
// Strings contains a list of strings that should be present in the
// response content
Strings []string `yaml:"strings,omitempty"`
// Status contains the numeric HTTP status code (e.g. 200 or 404) that
// should be returned in the HTTP response
Status *int `yaml:"status,omitempty"`
}
// headerEqual returns true if the supplied http.Response contains an expected
// HTTP header
func headerEqual(r *nethttp.Response, exp string) bool {
key, val, wantVal := strings.Cut(exp, ":")
_, ok := r.Header[key]
if !ok {
return false
}
if !wantVal {
// We were only looking for the Header key, didn't care about value.
return true
}
valGot := r.Header.Get(key)
if valGot == "" {
return false
}
// If the string being compared is of the form Key: Value,
// then we check for both existence and the value of the
// header
return strings.EqualFold(val, valGot)
}
// assertions contains all assertions made for the exec test
type assertions struct {
// failures contains the set of error messages for failed assertions
failures []error
// terminal indicates there was a failure in evaluating the assertions that
// should be considered a terminal condition (and therefore the test action
// should not be retried).
terminal bool
// exp contains the expected conditions to assert against
exp *Expect
// r is the `nethttp.Response` we will evaluate
r *nethttp.Response
// b is the body of the `nethttp.Response` we've read into a buffer
b []byte
}
// Fail appends a supplied error to the set of failed assertions
func (a *assertions) Fail(err error) {
a.failures = append(a.failures, err)
}
// Failures returns a slice of errors for all failed assertions
func (a *assertions) Failures() []error {
if a == nil {
return []error{}
}
return a.failures
}
// Terminal returns a bool indicating the assertions failed in a way that is
// not retryable.
func (a *assertions) Terminal() bool {
if a == nil {
return false
}
return a.terminal
}
// OK checks all the assertions against the supplied arguments and returns true
// if all assertions pass.
func (a *assertions) OK() bool {
if a.exp == nil {
return true
}
exp := a.exp
res := true
if exp.Status != nil {
got := a.r.StatusCode
if *exp.Status != got {
a.Fail(HTTPStatusNotEqual(*exp.Status, got))
return false
}
}
if exp.JSON != nil {
ja := gdtjson.New(exp.JSON, a.b)
if !ja.OK() {
a.terminal = ja.Terminal()
for _, f := range ja.Failures() {
a.Fail(f)
}
return false
}
}
if len(exp.Strings) > 0 {
for _, s := range exp.Strings {
if !strings.Contains(string(a.b), s) {
a.Fail(HTTPNotInBody(s))
return false
}
}
}
if len(exp.Headers) > 0 {
for _, header := range exp.Headers {
if !headerEqual(a.r, header) {
a.Fail(HTTPHeaderNotIn(header, a.r.Header))
return false
}
}
}
return res
}
// newAssertions returns an assertions object populated with the supplied http
// spec assertions
func newAssertions(
exp *Expect,
r *nethttp.Response,
b []byte,
) gdttypes.Assertions {
return &assertions{
failures: []error{},
exp: exp,
r: r,
b: b,
}
}