11package promapi_test
22
33import (
4- "fmt"
54 "net/http"
65 "net/http/httptest"
76 "strconv"
8- "strings"
97 "testing"
108 "time"
119
1210 "github.com/prometheus/client_golang/prometheus"
1311 "github.com/stretchr/testify/assert"
1412 "github.com/stretchr/testify/require"
13+ "go.nhat.io/httpmock"
1514
1615 "github.com/cloudflare/pint/internal/promapi"
1716)
1817
1918func TestConfig (t * testing.T ) {
20- srv := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
21- switch r .URL .Path {
22- case "/30s" + promapi .APIPathConfig :
23- w .WriteHeader (http .StatusOK )
24- w .Header ().Set ("Content-Type" , "application/json" )
25- _ , _ = w .Write ([]byte (`{"status":"success","data":{"yaml":"global:\n scrape_interval: 30s\n"}}` ))
26- case "/1m" + promapi .APIPathConfig :
27- w .WriteHeader (http .StatusOK )
28- w .Header ().Set ("Content-Type" , "application/json" )
29- _ , _ = w .Write ([]byte (`{"status":"success","data":{"yaml":"global:\n scrape_interval: 1m\n"}}` ))
30- case "/default" + promapi .APIPathConfig :
31- w .WriteHeader (http .StatusOK )
32- w .Header ().Set ("Content-Type" , "application/json" )
33- _ , _ = w .Write ([]byte (`{"status":"success","data":{"yaml":"global:\n {}\n"}}` ))
34- case "/once" + promapi .APIPathConfig :
35- w .WriteHeader (http .StatusOK )
36- w .Header ().Set ("Content-Type" , "application/json" )
37- _ , _ = w .Write ([]byte (`{"status":"success","data":{"yaml":"global:\n {}\n"}}` ))
38- case "/slow" + promapi .APIPathConfig :
39- w .WriteHeader (http .StatusOK )
40- w .Header ().Set ("Content-Type" , "application/json" )
41- time .Sleep (time .Second * 2 )
42- _ , _ = w .Write ([]byte (`{"status":"success","data":{"yaml":"global:\n {}\n"}}` ))
43- case "/error" + promapi .APIPathConfig :
44- w .WriteHeader (http .StatusInternalServerError )
45- _ , _ = w .Write ([]byte ("fake error\n " ))
46- case "/badYaml" + promapi .APIPathConfig :
47- w .WriteHeader (http .StatusOK )
48- w .Header ().Set ("Content-Type" , "application/json" )
49- _ , _ = w .Write ([]byte (`{"status":"success","data":{"yaml":"invalid yaml"}}` ))
50- case "/badJson" + promapi .APIPathConfig :
51- w .WriteHeader (http .StatusOK )
52- w .Header ().Set ("Content-Type" , "application/json" )
53- _ , _ = w .Write ([]byte (`{"status":"success","data":{"yaml"}}` ))
54- case "/apiError" + promapi .APIPathConfig :
55- w .WriteHeader (http .StatusOK )
56- w .Header ().Set ("Content-Type" , "application/json" )
57- _ , _ = w .Write ([]byte (`{"status":"error","errorType":"bad_data","error":"custom error message"}` ))
58- default :
59- w .WriteHeader (http .StatusBadRequest )
60- w .Header ().Set ("Content-Type" , "application/json" )
61- _ , _ = w .Write ([]byte (`{"status":"error","errorType":"bad_data","error":"unhandled path"}` ))
62- }
63- }))
64- t .Cleanup (srv .Close )
65-
6619 type testCaseT struct {
67- prefix string
68- err string
69- cfg promapi.ConfigResult
70- timeout time.Duration
20+ mock httpmock.Mocker
21+ errCheck func (t * testing.T , err error )
22+ name string
23+ cfg promapi.PrometheusConfig
24+ timeout time.Duration
7125 }
7226
7327 defaults := promapi.PrometheusConfig {
@@ -81,75 +35,147 @@ func TestConfig(t *testing.T) {
8135
8236 testCases := []testCaseT {
8337 {
84- prefix : "/ default" ,
38+ name : " default" ,
8539 timeout : time .Second ,
86- cfg : promapi.ConfigResult {
87- URI : srv .URL + "/default" ,
88- Config : defaults ,
89- },
40+ cfg : defaults ,
41+ mock : httpmock .New (func (s * httpmock.Server ) {
42+ s .ExpectGet (promapi .APIPathConfig ).
43+ ReturnHeader ("Content-Type" , "application/json" ).
44+ Return (`{"status":"success","data":{"yaml":"global:\n {}\n"}}` ).
45+ UnlimitedTimes ()
46+ }),
9047 },
9148 {
92- prefix : "/ 1m" ,
49+ name : " 1m" ,
9350 timeout : time .Second ,
94- cfg : promapi.ConfigResult {
95- URI : srv .URL + "/1m" ,
96- Config : defaults ,
97- },
51+ cfg : defaults ,
52+ mock : httpmock .New (func (s * httpmock.Server ) {
53+ s .ExpectGet (promapi .APIPathConfig ).
54+ ReturnHeader ("Content-Type" , "application/json" ).
55+ Return (`{"status":"success","data":{"yaml":"global:\n scrape_interval: 1m\n"}}` ).
56+ UnlimitedTimes ()
57+ }),
9858 },
9959 {
100- prefix : "/ 30s" ,
60+ name : " 30s" ,
10161 timeout : time .Second ,
102- cfg : promapi.ConfigResult {
103- URI : srv .URL + "/30s" ,
104- Config : promapi.PrometheusConfig {
105- Global : promapi.ConfigSectionGlobal {
106- ScrapeInterval : time .Second * 30 ,
107- ScrapeTimeout : time .Second * 10 ,
108- EvaluationInterval : time .Minute ,
109- ExternalLabels : nil ,
110- },
62+ cfg : promapi.PrometheusConfig {
63+ Global : promapi.ConfigSectionGlobal {
64+ ScrapeInterval : time .Second * 30 ,
65+ ScrapeTimeout : time .Second * 10 ,
66+ EvaluationInterval : time .Minute ,
67+ ExternalLabels : nil ,
11168 },
11269 },
70+ mock : httpmock .New (func (s * httpmock.Server ) {
71+ s .ExpectGet (promapi .APIPathConfig ).
72+ ReturnHeader ("Content-Type" , "application/json" ).
73+ Return (`{"status":"success","data":{"yaml":"global:\n scrape_interval: 30s\n"}}` ).
74+ UnlimitedTimes ()
75+ }),
11376 },
11477 {
115- prefix : "/ slow" ,
78+ name : " slow" ,
11679 timeout : time .Millisecond * 10 ,
117- err : "connection timeout" ,
80+ errCheck : func (t * testing.T , err error ) {
81+ t .Helper ()
82+ require .EqualError (t , err , "connection timeout" )
83+ },
84+ mock : httpmock .New (func (s * httpmock.Server ) {
85+ s .ExpectGet (promapi .APIPathConfig ).
86+ Run (func (_ * http.Request ) ([]byte , error ) {
87+ time .Sleep (time .Second * 2 )
88+ return []byte (`{"status":"success","data":{"yaml":"global:\n {}\n"}}` ), nil
89+ }).
90+ UnlimitedTimes ()
91+ }),
11892 },
11993 {
120- prefix : "/ error" ,
94+ name : " error" ,
12195 timeout : time .Second ,
122- err : "server_error: 500 Internal Server Error" ,
96+ errCheck : func (t * testing.T , err error ) {
97+ t .Helper ()
98+ require .EqualError (t , err , "server_error: 500 Internal Server Error" )
99+ },
100+ mock : httpmock .New (func (s * httpmock.Server ) {
101+ s .ExpectGet (promapi .APIPathConfig ).
102+ ReturnCode (http .StatusInternalServerError ).
103+ Return ("fake error\n " ).
104+ UnlimitedTimes ()
105+ }),
123106 },
124107 {
125- prefix : "/ badYaml" ,
108+ name : " badYaml" ,
126109 timeout : time .Second ,
127- err : fmt .Sprintf ("failed to decode config data in %s/badYaml response: yaml: unmarshal errors:\n line 1: cannot unmarshal !!str `invalid...` into promapi.PrometheusConfig" , srv .URL ),
110+ errCheck : func (t * testing.T , err error ) {
111+ t .Helper ()
112+ require .ErrorContains (t , err , "failed to decode config data in" )
113+ },
114+ mock : httpmock .New (func (s * httpmock.Server ) {
115+ s .ExpectGet (promapi .APIPathConfig ).
116+ ReturnHeader ("Content-Type" , "application/json" ).
117+ Return (`{"status":"success","data":{"yaml":"invalid yaml"}}` ).
118+ UnlimitedTimes ()
119+ }),
128120 },
129121 {
130- prefix : "/ badJson" ,
122+ name : " badJson" ,
131123 timeout : time .Second ,
132- err : `bad_response: JSON parse error: jsontext: invalid character '}' after object name (expecting ':') within "/data/yaml" after offset 34` ,
124+ errCheck : func (t * testing.T , err error ) {
125+ t .Helper ()
126+ require .EqualError (t , err , `bad_response: JSON parse error: jsontext: invalid character '}' after object name (expecting ':') within "/data/yaml" after offset 34` )
127+ },
128+ mock : httpmock .New (func (s * httpmock.Server ) {
129+ s .ExpectGet (promapi .APIPathConfig ).
130+ ReturnHeader ("Content-Type" , "application/json" ).
131+ Return (`{"status":"success","data":{"yaml"}}` ).
132+ UnlimitedTimes ()
133+ }),
133134 },
134135 {
135- prefix : "/ apiError" ,
136+ name : " apiError" ,
136137 timeout : time .Second ,
137- err : "bad_data: custom error message" ,
138+ errCheck : func (t * testing.T , err error ) {
139+ t .Helper ()
140+ require .EqualError (t , err , "bad_data: custom error message" )
141+ },
142+ mock : httpmock .New (func (s * httpmock.Server ) {
143+ s .ExpectGet (promapi .APIPathConfig ).
144+ ReturnHeader ("Content-Type" , "application/json" ).
145+ Return (`{"status":"error","errorType":"bad_data","error":"custom error message"}` ).
146+ UnlimitedTimes ()
147+ }),
148+ },
149+ {
150+ name : "emptyError" ,
151+ timeout : time .Second ,
152+ errCheck : func (t * testing.T , err error ) {
153+ t .Helper ()
154+ require .EqualError (t , err , "bad_data: empty response object" )
155+ },
156+ mock : httpmock .New (func (s * httpmock.Server ) {
157+ s .ExpectGet (promapi .APIPathConfig ).
158+ ReturnHeader ("Content-Type" , "application/json" ).
159+ Return (`{"status":"error","errorType":"bad_data"}` ).
160+ UnlimitedTimes ()
161+ }),
138162 },
139163 }
140164
141165 for _ , tc := range testCases {
142- t .Run (strings .TrimPrefix (tc .prefix , "/" ), func (t * testing.T ) {
143- prom := promapi .NewPrometheus ("test" , srv .URL + tc .prefix , "" , nil , tc .timeout , 1 , 100 , nil )
166+ t .Run (tc .name , func (t * testing.T ) {
167+ srv := tc .mock (t )
168+
169+ prom := promapi .NewPrometheus ("test" , srv .URL (), "" , nil , tc .timeout , 1 , 100 , nil )
144170 prom .StartWorkers ()
145171 t .Cleanup (prom .Close )
146172
147173 cfg , err := prom .Config (t .Context (), time .Minute )
148- if tc .err != "" {
149- require . EqualError (t , err , tc . err , tc )
174+ if tc .errCheck != nil {
175+ tc . errCheck (t , err )
150176 } else {
151177 require .NoError (t , err )
152- require .Equal (t , * cfg , tc . cfg )
178+ require .Equal (t , tc . cfg , cfg . Config )
153179 }
154180 })
155181 }
0 commit comments