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

raystack / meteor / 6291986723

24 Sep 2023 07:30PM UTC coverage: 83.215% (+9.5%) from 73.754%
6291986723

push

github

web-flow
chore: fix bigquery plugin test (#484)

6782 of 8150 relevant lines covered (83.21%)

0.92 hits per line

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

86.67
/plugins/extractors/http/execute_request.go
1
package http
2

3
import (
4
        "bytes"
5
        "context"
6
        "encoding/json"
7
        "fmt"
8
        "io"
9
        "net/http"
10
        "strings"
11

12
        "github.com/raystack/meteor/metrics/otelhttpclient"
13
)
14

15
type executeRequestFunc func(ctx context.Context, reqCfg RequestConfig) (map[string]interface{}, error)
16

17
func makeRequestExecutor(successCodes []int, httpClient *http.Client) executeRequestFunc {
1✔
18
        return func(ctx context.Context, reqCfg RequestConfig) (map[string]interface{}, error) {
2✔
19
                ctx, cancel := context.WithTimeout(ctx, reqCfg.Timeout)
1✔
20
                defer cancel()
1✔
21

1✔
22
                req, err := buildRequest(ctx, reqCfg)
1✔
23
                if err != nil {
1✔
24
                        return nil, err
×
25
                }
×
26

27
                resp, err := httpClient.Do(req)
1✔
28
                defer drainBody(resp)
1✔
29
                if err != nil {
2✔
30
                        return nil, fmt.Errorf("do request: %w", err)
1✔
31
                }
1✔
32

33
                return handleResponse(successCodes, resp)
1✔
34
        }
35
}
36

37
func buildRequest(ctx context.Context, reqCfg RequestConfig) (*http.Request, error) {
1✔
38
        body, err := asReader(reqCfg.Body)
1✔
39
        if err != nil {
1✔
40
                return nil, fmt.Errorf("encode request body: %w", err)
×
41
        }
×
42

43
        req, err := http.NewRequestWithContext(ctx, reqCfg.Method, reqCfg.URL, body)
1✔
44
        if err != nil {
1✔
45
                return nil, fmt.Errorf("create HTTP request: %w", err)
×
46
        }
×
47

48
        addQueryParams(req, reqCfg.QueryParams)
1✔
49

1✔
50
        for name, v := range reqCfg.Headers {
2✔
51
                req.Header.Set(name, v)
1✔
52
        }
1✔
53
        if req.Body != nil && req.Body != http.NoBody {
2✔
54
                req.Header.Set("Content-Type", "application/json")
1✔
55
        }
1✔
56
        req.Header.Set("Accept", "application/json")
1✔
57

1✔
58
        return otelhttpclient.AnnotateRequest(req, reqCfg.RoutePattern), nil
1✔
59
}
60

61
func addQueryParams(req *http.Request, params []QueryParam) {
1✔
62
        if len(params) == 0 {
2✔
63
                return
1✔
64
        }
1✔
65

66
        q := req.URL.Query()
1✔
67
        // First delete any possible conflicts. Cannot be done in a single loop
1✔
68
        // because params can have multiple entries with the same key.
1✔
69
        for _, p := range params {
2✔
70
                q.Del(p.Key)
1✔
71
        }
1✔
72
        for _, p := range params {
2✔
73
                q.Add(p.Key, p.Value)
1✔
74
        }
1✔
75
        req.URL.RawQuery = q.Encode()
1✔
76
}
77

78
func handleResponse(successCodes []int, resp *http.Response) (map[string]interface{}, error) {
1✔
79
        if !has(successCodes, resp.StatusCode) {
2✔
80
                return nil, fmt.Errorf("unsuccessful request: response status code: %d", resp.StatusCode)
1✔
81
        }
1✔
82

83
        h := make(map[string]interface{}, len(resp.Header))
1✔
84
        for k := range resp.Header {
2✔
85
                h[strings.ToLower(k)] = resp.Header.Get(k)
1✔
86
        }
1✔
87

88
        var body interface{}
1✔
89
        if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
1✔
90
                return nil, fmt.Errorf("decode response: %w", err)
×
91
        }
×
92

93
        return map[string]interface{}{
1✔
94
                "status_code": resp.StatusCode,
1✔
95
                "header":      h,
1✔
96
                "body":        body,
1✔
97
        }, nil
1✔
98
}
99

100
func asReader(v interface{}) (io.Reader, error) {
1✔
101
        if v == nil {
2✔
102
                return nil, nil
1✔
103
        }
1✔
104

105
        if body, ok := v.(string); ok {
1✔
106
                return bytes.NewBufferString(body), nil
×
107
        }
×
108

109
        var buf bytes.Buffer
1✔
110
        if err := json.NewEncoder(&buf).Encode(v); err != nil {
1✔
111
                return nil, err
×
112
        }
×
113

114
        return &buf, nil
1✔
115
}
116

117
// drainBody drains and closes the response body to avoid the following
118
// gotcha:
119
// http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/index.html#close_http_resp_body
120
func drainBody(resp *http.Response) {
1✔
121
        if resp == nil {
2✔
122
                return
1✔
123
        }
1✔
124

125
        _, _ = io.Copy(io.Discard, resp.Body)
1✔
126
        _ = resp.Body.Close()
1✔
127
}
128

129
func has(haystack []int, needle int) bool {
1✔
130
        for _, n := range haystack {
2✔
131
                if n == needle {
2✔
132
                        return true
1✔
133
                }
1✔
134
        }
135

136
        return false
1✔
137
}
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