This repository has been archived by the owner on Jun 13, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathmmock.go
143 lines (131 loc) · 3.75 KB
/
mmock.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
package gandalf
import (
"encoding/json"
"io/ioutil"
"net/http"
"path"
"time"
"github.com/jmartin82/mmock/definition"
)
// ToMMock exports Contract as MMock definitions to build a fake api endpoint
// with optional state via MMock scenarios. MMock
// (https://github.com/jmartin82/mmock) is an http mocking server.
type ToMMock struct {
// The state(s) that the Scenario must be in to trigger this mock.
TriggerStates []string
// The Scenario to which state is stored.
Scenario string
// The state to transition the scenario to when this mock is triggered.
NewState string
// When set this is used for the request path definition instead of the path from the Contract's Requestor.
Path string
// Enables chaos testing by causing the mock, when triggered, may return a 5xx instead.
ChaoticEvil bool
// If true MMock will require the request headers to match exactly to trigger this mock.
// This should be left false (the default ) for dynamic headers such as tokens/id's.
MatchHeaders bool
// If true MMock will require the request body to match exactly to trigger this mock.
// This should be left false (the default ) for dynamic requests such as tokens/id's.
MatchBody bool
saved bool
}
func headersToValues(h map[string][]string) definition.Values {
return h
}
func cookiesToMap(cs []*http.Cookie) map[string]string {
out := map[string]string{}
for _, c := range cs {
out[c.Name] = c.Value
}
return out
}
func (m *ToMMock) translateRequest(req *http.Request) definition.Request {
out := definition.Request{
Path: req.URL.Path,
Method: req.Method,
}
if m.Path != "" {
out.Path = m.Path
}
if m.MatchHeaders {
out.HttpHeaders = definition.HttpHeaders{
Headers: headersToValues(req.Header),
Cookies: cookiesToMap(req.Cookies()),
}
}
if m.MatchBody {
out.Body = GetRequestBody(req)
}
return out
}
func (m *ToMMock) translateResponse(resp *http.Response) definition.Response {
return definition.Response{
StatusCode: resp.StatusCode,
HttpHeaders: definition.HttpHeaders{
Headers: headersToValues(resp.Header),
Cookies: cookiesToMap(resp.Cookies()),
},
Body: GetResponseBody(resp),
}
}
func (m *ToMMock) translateMock() definition.Control {
out := definition.Control{
Crazy: OverrideChaos || m.ChaoticEvil,
}
if m.Scenario != "" {
out.Scenario = definition.Scenario{
Name: m.Scenario,
}
if len(m.TriggerStates) > 0 {
out.Scenario.RequiredState = m.TriggerStates
}
if m.NewState != "" {
out.Scenario.NewState = m.NewState
}
}
return out
}
// Uses Requester.GetRequest and Checker.GetResponse as a basis to build
// an MMock definition.
func (m *ToMMock) contractToMock(c *Contract) definition.Mock {
return definition.Mock{
URI: c.Name + ".json",
Description: c.Name,
Request: m.translateRequest(c.Request.GetRequest()),
Response: m.translateResponse(c.Check.GetResponse()),
Control: m.translateMock(),
}
}
func (m *ToMMock) saveMockToFile(mock definition.Mock) error {
out, err := json.Marshal(mock)
if err != nil {
return err
}
err = ioutil.WriteFile(path.Join(MockSavePath, mock.Description+".json"), out, 0644)
if err != nil {
return err
}
time.Sleep(time.Duration(MockDelay) * time.Millisecond)
m.saved = true
return err
}
func (m *ToMMock) saveMockToAPI(mock definition.Mock) error {
api := getMMockClient()
if e := api.upsertDefinition(mock); e != nil {
return e
}
m.saved = true
return nil
}
// Save a valid MMock definition to a json file with the contract name as the filename.
// This incurs disk IO so is restricted to only saving once per instance.
func (m *ToMMock) Save(c *Contract) error {
if m.saved || c.Tested || MockSkip {
return nil
}
saver := m.saveMockToFile
if mockSaveAPI() {
saver = m.saveMockToAPI
}
return saver(m.contractToMock(c))
}