• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

go-pkgz / testutils / 13672966962

05 Mar 2025 09:40AM UTC coverage: 85.393% (+4.2%) from 81.176%
13672966962

push

github

web-flow
Merge pull request #1 from go-pkgz/add-test-utilities

Add file and HTTP test utilities

83 of 93 new or added lines in 2 files covered. (89.25%)

152 of 178 relevant lines covered (85.39%)

2.48 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.74
/http_utils.go
1
package testutils
2

3
import (
4
        "bytes"
5
        "io"
6
        "net/http"
7
        "net/http/httptest"
8
        "sync"
9
        "testing"
10
)
11

12
// MockHTTPServer creates a test HTTP server with the given handler.
13
// Returns the server URL and a function to close it.
14
func MockHTTPServer(t *testing.T, handler http.Handler) (serverURL string, cleanup func()) {
2✔
15
        t.Helper()
2✔
16

2✔
17
        server := httptest.NewServer(handler)
2✔
18

2✔
19
        cleanup = func() {
5✔
20
                server.Close()
3✔
21
        }
3✔
22

23
        // register cleanup with t.Cleanup to ensure the server is closed
24
        // even if the test fails
25
        t.Cleanup(cleanup)
2✔
26

2✔
27
        return server.URL, cleanup
2✔
28
}
29

30
// RequestRecord holds information about a captured HTTP request
31
type RequestRecord struct {
32
        Method  string
33
        Path    string
34
        Headers http.Header
35
        Body    []byte
36
}
37

38
// RequestCaptor captures HTTP requests for inspection in tests
39
type RequestCaptor struct {
40
        mu       sync.Mutex
41
        requests []RequestRecord
42
}
43

44
// Len returns the number of captured requests
45
func (c *RequestCaptor) Len() int {
2✔
46
        c.mu.Lock()
2✔
47
        defer c.mu.Unlock()
2✔
48
        return len(c.requests)
2✔
49
}
2✔
50

51
// GetRequest returns the request at the specified index
52
func (c *RequestCaptor) GetRequest(idx int) (RequestRecord, bool) {
3✔
53
        c.mu.Lock()
3✔
54
        defer c.mu.Unlock()
3✔
55

3✔
56
        if idx < 0 || idx >= len(c.requests) {
3✔
NEW
57
                return RequestRecord{}, false
×
NEW
58
        }
×
59

60
        return c.requests[idx], true
3✔
61
}
62

63
// GetRequests returns all captured requests
64
func (c *RequestCaptor) GetRequests() []RequestRecord {
1✔
65
        c.mu.Lock()
1✔
66
        defer c.mu.Unlock()
1✔
67

1✔
68
        // return a copy to avoid race conditions
1✔
69
        result := make([]RequestRecord, len(c.requests))
1✔
70
        copy(result, c.requests)
1✔
71
        return result
1✔
72
}
1✔
73

74
// Reset clears all captured requests
75
func (c *RequestCaptor) Reset() {
1✔
76
        c.mu.Lock()
1✔
77
        defer c.mu.Unlock()
1✔
78
        c.requests = nil
1✔
79
}
1✔
80

81
// add records a new request
82
func (c *RequestCaptor) add(rec RequestRecord) {
3✔
83
        c.mu.Lock()
3✔
84
        defer c.mu.Unlock()
3✔
85
        c.requests = append(c.requests, rec)
3✔
86
}
3✔
87

88
// HTTPRequestCaptor returns a request captor and HTTP handler that captures requests
89
// The returned handler will forward requests to the provided next handler if not nil
90
func HTTPRequestCaptor(t *testing.T, next http.Handler) (*RequestCaptor, http.Handler) {
1✔
91
        t.Helper()
1✔
92

1✔
93
        captor := &RequestCaptor{
1✔
94
                requests: []RequestRecord{},
1✔
95
        }
1✔
96

1✔
97
        handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
4✔
98
                // create a record from the request
3✔
99
                record := RequestRecord{
3✔
100
                        Method:  r.Method,
3✔
101
                        Path:    r.URL.Path,
3✔
102
                        Headers: r.Header.Clone(),
3✔
103
                }
3✔
104

3✔
105
                // read and store the body if present
3✔
106
                if r.Body != nil {
6✔
107
                        // read body
3✔
108
                        bodyBytes, err := io.ReadAll(r.Body)
3✔
109
                        if err != nil {
3✔
NEW
110
                                t.Logf("failed to read request body: %v", err)
×
NEW
111
                        }
×
112

113
                        // store the body in the record
114
                        record.Body = bodyBytes
3✔
115

3✔
116
                        // replace the body for downstream handlers
3✔
117
                        r.Body = io.NopCloser(bytes.NewReader(bodyBytes))
3✔
118
                }
119

120
                // add the record to the captor
121
                captor.add(record)
3✔
122

3✔
123
                // forward the request if a next handler is provided
3✔
124
                if next != nil {
6✔
125
                        next.ServeHTTP(w, r)
3✔
126
                }
3✔
127
        })
128

129
        return captor, handler
1✔
130
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc