cloudflare/pint

Public

mirrored from https://github.com/cloudflare/pintAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.81.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

internal/promapi/buildinfo_test.go

122lines · modecode

1package promapi_test
2
3import (
4 "net/http"
5 "testing"
6 "time"
7
8 "github.com/prometheus/client_golang/prometheus"
9 "github.com/stretchr/testify/require"
10 "go.nhat.io/httpmock"
11
12 "github.com/cloudflare/pint/internal/promapi"
13)
14
15func TestBuildInfo(t *testing.T) {
16 type testCaseT struct {
17 mock httpmock.Mocker
18 name string
19 version string
20 err string
21 timeout time.Duration
22 }
23
24 testCases := []testCaseT{
25 // Verifies that a valid buildinfo response is parsed correctly.
26 {
27 name: "success",
28 timeout: time.Second,
29 version: "2.49.0",
30 mock: httpmock.New(func(s *httpmock.Server) {
31 s.ExpectGet(promapi.APIPathBuildInfo).
32 ReturnHeader("Content-Type", "application/json").
33 Return(`{"status":"success","data":{"version":"2.49.0","revision":"abc","branch":"HEAD","buildUser":"","buildDate":"","goVersion":"go1.21"}}`).
34 UnlimitedTimes()
35 }),
36 },
37 // Verifies that a request timeout produces a connection timeout error.
38 {
39 name: "slow",
40 timeout: time.Millisecond * 10,
41 err: "connection timeout",
42 mock: httpmock.New(func(s *httpmock.Server) {
43 s.ExpectGet(promapi.APIPathBuildInfo).
44 Run(func(_ *http.Request) ([]byte, error) {
45 time.Sleep(time.Second * 2)
46 return []byte(`{"status":"success","data":{"version":"2.49.0","revision":"abc","branch":"HEAD","buildUser":"","buildDate":"","goVersion":"go1.21"}}`), nil
47 }).
48 UnlimitedTimes()
49 }),
50 },
51 // Verifies that a non-2xx HTTP status produces a server error.
52 {
53 name: "error",
54 timeout: time.Second,
55 err: "server_error: 500 Internal Server Error",
56 mock: httpmock.New(func(s *httpmock.Server) {
57 s.ExpectGet(promapi.APIPathBuildInfo).
58 ReturnCode(http.StatusInternalServerError).
59 Return("fake error\n").
60 UnlimitedTimes()
61 }),
62 },
63 // Verifies that invalid JSON produces a bad_response error.
64 {
65 name: "badJson",
66 timeout: time.Second,
67 err: `bad_response: JSON parse error: invalid character '}' after object key`,
68 mock: httpmock.New(func(s *httpmock.Server) {
69 s.ExpectGet(promapi.APIPathBuildInfo).
70 ReturnHeader("Content-Type", "application/json").
71 Return(`{"status":"success","data":{"xxx"}}`).
72 UnlimitedTimes()
73 }),
74 },
75 // Verifies that an API-level error with a custom message is forwarded.
76 {
77 name: "apiError",
78 timeout: time.Second,
79 err: `bad_data: custom error message`,
80 mock: httpmock.New(func(s *httpmock.Server) {
81 s.ExpectGet(promapi.APIPathBuildInfo).
82 ReturnHeader("Content-Type", "application/json").
83 Return(`{"status":"error","errorType":"bad_data","error":"custom error message"}`).
84 UnlimitedTimes()
85 }),
86 },
87 // Verifies that an API-level error without a message uses the fallback.
88 {
89 name: "emptyError",
90 timeout: time.Second,
91 err: `bad_data: empty response object`,
92 mock: httpmock.New(func(s *httpmock.Server) {
93 s.ExpectGet(promapi.APIPathBuildInfo).
94 ReturnHeader("Content-Type", "application/json").
95 Return(`{"status":"error","errorType":"bad_data"}`).
96 UnlimitedTimes()
97 }),
98 },
99 }
100
101 for _, tc := range testCases {
102 t.Run(tc.name, func(t *testing.T) {
103 srv := tc.mock(t)
104
105 fg := promapi.NewFailoverGroup("test", srv.URL(), []*promapi.Prometheus{
106 promapi.NewPrometheus("test", srv.URL(), "", nil, tc.timeout, 1, 100, nil),
107 }, true, "up", nil, nil, nil)
108
109 reg := prometheus.NewRegistry()
110 fg.StartWorkers(reg)
111 defer fg.Close(reg)
112
113 bi, err := fg.BuildInfo(t.Context())
114 if tc.err != "" {
115 require.EqualError(t, err, tc.err, tc)
116 } else {
117 require.NoError(t, err)
118 require.Equal(t, tc.version, bi.Version)
119 }
120 })
121 }
122}