1
16
17 package main
18
19 import (
20 "bytes"
21 "encoding/json"
22 "fmt"
23 "io"
24 "net/http"
25 "os"
26 "strings"
27
28 yaml "gopkg.in/yaml.v2"
29 )
30
31 type EditTestCase struct {
32 Description string `yaml:"description"`
33
34 Mode string `yaml:"mode"`
35 Args []string `yaml:"args"`
36 Filename string `yaml:"filename"`
37 Output string `yaml:"outputFormat"`
38 Namespace string `yaml:"namespace"`
39 ExpectedStdout []string `yaml:"expectedStdout"`
40 ExpectedStderr []string `yaml:"expectedStderr"`
41 ExpectedExitCode int `yaml:"expectedExitCode"`
42
43 Steps []EditStep `yaml:"steps"`
44 }
45
46 type EditStep struct {
47
48 StepType string `yaml:"type"`
49
50
51 RequestMethod string `yaml:"expectedMethod,omitempty"`
52 RequestPath string `yaml:"expectedPath,omitempty"`
53 RequestContentType string `yaml:"expectedContentType,omitempty"`
54 Input string `yaml:"expectedInput"`
55
56
57 ResponseStatusCode int `yaml:"resultingStatusCode,omitempty"`
58
59 Output string `yaml:"resultingOutput"`
60 }
61
62 func main() {
63 tc := &EditTestCase{
64 Description: "add a testcase description",
65 Mode: "edit",
66 Args: []string{"set", "args"},
67 ExpectedStdout: []string{"expected stdout substring"},
68 ExpectedStderr: []string{"expected stderr substring"},
69 }
70
71 var currentStep *EditStep
72
73 fmt.Println(http.ListenAndServe(":8081", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
74
75
76 record := false
77 switch segments := strings.Split(strings.Trim(req.URL.Path, "/"), "/"); segments[0] {
78 case "api":
79
80 record = len(segments) > 2
81 case "apis":
82
83 record = len(segments) > 3
84 case "callback":
85 record = true
86 }
87
88 body, err := io.ReadAll(req.Body)
89 checkErr(err)
90
91 switch m, p := req.Method, req.URL.Path; {
92 case m == "POST" && p == "/callback/in":
93 if currentStep != nil {
94 panic("cannot post input with step already in progress")
95 }
96 filename := fmt.Sprintf("%d.original", len(tc.Steps))
97 checkErr(os.WriteFile(filename, body, os.FileMode(0755)))
98 currentStep = &EditStep{StepType: "edit", Input: filename}
99 case m == "POST" && p == "/callback/out":
100 if currentStep == nil || currentStep.StepType != "edit" {
101 panic("cannot post output without posting input first")
102 }
103 filename := fmt.Sprintf("%d.edited", len(tc.Steps))
104 checkErr(os.WriteFile(filename, body, os.FileMode(0755)))
105 currentStep.Output = filename
106 tc.Steps = append(tc.Steps, *currentStep)
107 currentStep = nil
108 default:
109 if currentStep != nil {
110 panic("cannot make request with step already in progress")
111 }
112
113 urlCopy := *req.URL
114 urlCopy.Host = "localhost:8080"
115 urlCopy.Scheme = "http"
116 proxiedReq, err := http.NewRequest(req.Method, urlCopy.String(), bytes.NewReader(body))
117 checkErr(err)
118 proxiedReq.Header = req.Header
119 resp, err := http.DefaultClient.Do(proxiedReq)
120 checkErr(err)
121 defer resp.Body.Close()
122
123 bodyOut, err := io.ReadAll(resp.Body)
124 checkErr(err)
125
126 for k, vs := range resp.Header {
127 for _, v := range vs {
128 w.Header().Add(k, v)
129 }
130 }
131 w.WriteHeader(resp.StatusCode)
132 w.Write(bodyOut)
133
134 if record {
135 infile := fmt.Sprintf("%d.request", len(tc.Steps))
136 outfile := fmt.Sprintf("%d.response", len(tc.Steps))
137 checkErr(os.WriteFile(infile, tryIndent(body), os.FileMode(0755)))
138 checkErr(os.WriteFile(outfile, tryIndent(bodyOut), os.FileMode(0755)))
139 tc.Steps = append(tc.Steps, EditStep{
140 StepType: "request",
141 Input: infile,
142 Output: outfile,
143 RequestContentType: req.Header.Get("Content-Type"),
144 RequestMethod: req.Method,
145 RequestPath: req.URL.Path,
146 ResponseStatusCode: resp.StatusCode,
147 })
148 }
149 }
150
151 tcData, err := yaml.Marshal(tc)
152 checkErr(err)
153 checkErr(os.WriteFile("test.yaml", tcData, os.FileMode(0755)))
154 })))
155 }
156
157 func checkErr(err error) {
158 if err != nil {
159 panic(err)
160 }
161 }
162
163 func tryIndent(data []byte) []byte {
164 indented := &bytes.Buffer{}
165 if err := json.Indent(indented, data, "", "\t"); err == nil {
166 return indented.Bytes()
167 }
168 return data
169 }
170
View as plain text