1
1
package main
2
2
3
3
import (
4
+ "bytes"
4
5
"context"
5
6
"crypto/rand"
6
7
"crypto/rsa"
@@ -9,18 +10,21 @@ import (
9
10
"encoding/pem"
10
11
"errors"
11
12
"fmt"
13
+ "io"
12
14
"math/big"
13
15
"net"
14
16
"net/http"
15
17
"os"
16
18
"path"
17
19
"regexp"
20
+ "slices"
18
21
"strconv"
19
22
"strings"
20
23
"sync"
21
24
"testing"
22
25
"time"
23
26
27
+ "github.com/itchyny/json2yaml"
24
28
"github.com/rogpeppe/go-internal/testscript"
25
29
)
26
30
@@ -54,7 +58,6 @@ func httpServer(ts *testscript.TestScript, _ bool, args []string) {
54
58
cmd := args [0 ]
55
59
56
60
switch cmd {
57
- // http response name /200 200 OK
58
61
case "response" :
59
62
if len (args ) < 5 {
60
63
ts .Fatalf ("! http response command requires '$NAME $PATH $CODE $BODY' args, got [%s]" , strings .Join (args , " " ))
@@ -64,9 +67,10 @@ func httpServer(ts *testscript.TestScript, _ bool, args []string) {
64
67
code , err := strconv .Atoi (args [3 ])
65
68
ts .Check (err )
66
69
body := strings .Join (args [4 :], " " )
67
- mocks .add (name , httpMock {pattern : path , handler : func (w http.ResponseWriter , _ * http.Request ) {
70
+ mocks .add (name , httpMock {pattern : path , handler : func (w http.ResponseWriter , r * http.Request ) {
71
+ snapshotRequest (ts , r , name , path )
68
72
w .WriteHeader (code )
69
- _ , err : = w .Write ([]byte (body ))
73
+ _ , err = w .Write ([]byte (body ))
70
74
ts .Check (err )
71
75
}})
72
76
case "method" :
@@ -79,7 +83,8 @@ func httpServer(ts *testscript.TestScript, _ bool, args []string) {
79
83
code , err := strconv .Atoi (args [4 ])
80
84
ts .Check (err )
81
85
body := strings .Join (args [5 :], " " )
82
- mocks .add (name , httpMock {pattern : path , method : meth , handler : func (w http.ResponseWriter , _ * http.Request ) {
86
+ mocks .add (name , httpMock {pattern : path , method : meth , handler : func (w http.ResponseWriter , r * http.Request ) {
87
+ snapshotRequest (ts , r , name , path )
83
88
w .WriteHeader (code )
84
89
_ , err := w .Write ([]byte (body ))
85
90
ts .Check (err )
@@ -99,6 +104,7 @@ func httpServer(ts *testscript.TestScript, _ bool, args []string) {
99
104
mocks .add (name , httpMock {pattern : path , handler : func (w http.ResponseWriter , r * http.Request ) {
100
105
username , password , ok := r .BasicAuth ()
101
106
if ok && username == user && password == pass {
107
+ snapshotRequest (ts , r , name , path )
102
108
w .WriteHeader (code )
103
109
_ , err := w .Write ([]byte (body ))
104
110
ts .Check (err )
@@ -118,7 +124,8 @@ func httpServer(ts *testscript.TestScript, _ bool, args []string) {
118
124
code , err := strconv .Atoi (args [4 ])
119
125
ts .Check (err )
120
126
body := strings .Join (args [5 :], " " )
121
- mocks .add (name , httpMock {pattern : path , handler : func (w http.ResponseWriter , _ * http.Request ) {
127
+ mocks .add (name , httpMock {pattern : path , handler : func (w http.ResponseWriter , r * http.Request ) {
128
+ snapshotRequest (ts , r , name , path )
122
129
time .Sleep (delay )
123
130
w .WriteHeader (code )
124
131
_ , err := w .Write ([]byte (body ))
@@ -132,7 +139,8 @@ func httpServer(ts *testscript.TestScript, _ bool, args []string) {
132
139
name := args [1 ]
133
140
srcpath := regexp .MustCompile (args [2 ])
134
141
dstpath := args [3 ]
135
- mocks .add (name , httpMock {pattern : srcpath , handler : func (w http.ResponseWriter , _ * http.Request ) {
142
+ mocks .add (name , httpMock {pattern : srcpath , handler : func (w http.ResponseWriter , r * http.Request ) {
143
+ snapshotRequest (ts , r , name , srcpath )
136
144
w .Header ().Set ("Location" , dstpath )
137
145
w .WriteHeader (http .StatusFound )
138
146
}})
@@ -151,6 +159,7 @@ func httpServer(ts *testscript.TestScript, _ bool, args []string) {
151
159
tlsKey = args [4 ]
152
160
}
153
161
162
+ var mtx sync.Mutex
154
163
mux := http .NewServeMux ()
155
164
mux .Handle ("/" , http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
156
165
var done bool
@@ -163,8 +172,10 @@ func httpServer(ts *testscript.TestScript, _ bool, args []string) {
163
172
if ! mock .pattern .MatchString (r .URL .Path ) {
164
173
continue
165
174
}
175
+ mtx .Lock ()
166
176
mock .handler (w , r )
167
177
done = true
178
+ mtx .Unlock ()
168
179
break
169
180
}
170
181
break
@@ -331,3 +342,67 @@ func writeCert(ts *testscript.TestScript, dirname, filename string, block *pem.B
331
342
332
343
ts .Logf ("Wrote PEM file to %s" , filename )
333
344
}
345
+
346
+ func snapshotRequest (ts * testscript.TestScript , r * http.Request , name string , path * regexp.Regexp ) {
347
+ payload , err := io .ReadAll (r .Body )
348
+ ts .Check (err )
349
+ r .Body .Close ()
350
+
351
+ var buf strings.Builder
352
+ buf .WriteString (r .Method )
353
+ buf .WriteRune (' ' )
354
+ buf .WriteString (path .String ())
355
+ buf .WriteRune ('\n' )
356
+
357
+ hKeys := make ([]string , 0 , len (r .Header ))
358
+ for k := range r .Header {
359
+ if k == "Content-Length" || k == "User-Agent" {
360
+ continue
361
+ }
362
+ hKeys = append (hKeys , k )
363
+ }
364
+ slices .Sort (hKeys )
365
+ for _ , k := range hKeys {
366
+ buf .WriteString (" " )
367
+ buf .WriteString (k )
368
+ buf .WriteRune (':' )
369
+ buf .WriteRune (' ' )
370
+ buf .WriteString (strings .Join (r .Header .Values (k ), ";" ))
371
+ buf .WriteRune ('\n' )
372
+ }
373
+
374
+ if len (payload ) > 0 {
375
+ payload = sanitizePayload (payload )
376
+ buf .WriteString ("--- BODY ---\n " )
377
+ buf .Write (payload )
378
+ if ! bytes .HasSuffix (payload , []byte ("\n " )) {
379
+ buf .WriteRune ('\n' )
380
+ }
381
+ buf .WriteString ("--- END ---\n " )
382
+ }
383
+ buf .WriteRune ('\n' )
384
+
385
+ f , err := os .OpenFile (ts .MkAbs (name + ".got" ), os .O_APPEND | os .O_WRONLY | os .O_CREATE , 0o644 )
386
+ ts .Check (err )
387
+ _ , err = f .WriteString (buf .String ())
388
+ ts .Check (err )
389
+ ts .Check (f .Close ())
390
+ }
391
+
392
+ func sanitizePayload (payload []byte ) []byte {
393
+ bbDurationRe := regexp .MustCompile (`\{"value":([0-9]+),"title":"Checks duration","type":"DURATION"\}` )
394
+ payload = bbDurationRe .ReplaceAll (payload , []byte (`{"value":0,"title":"Checks duration","type":"DURATION"}` ))
395
+
396
+ ghDurationRe := regexp .MustCompile (`\| Checks duration \| ([0-9]+[a-z]+) \|` )
397
+ payload = ghDurationRe .ReplaceAll (payload , []byte (`| Checks duration | 0 |` ))
398
+
399
+ commitIDRe := regexp .MustCompile (`"commit_id":"([0-9a-zA-Z]{40})"` )
400
+ payload = commitIDRe .ReplaceAll (payload , []byte (`"commit_id":"<COMMIT ID>"` ))
401
+
402
+ var output bytes.Buffer
403
+ if err := json2yaml .Convert (& output , bytes .NewReader (payload )); err != nil {
404
+ return payload
405
+ }
406
+
407
+ return output .Bytes ()
408
+ }
0 commit comments