mirror of
https://github.com/prometheus/prometheus.git
synced 2026-03-22 10:30:25 -04:00
145 lines
4.1 KiB
Go
145 lines
4.1 KiB
Go
// Copyright The Prometheus Authors
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
// This file provides HTTP request builders for testing API endpoints.
|
|
package testhelpers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// Response wraps an HTTP response with parsed JSON data.
|
|
// It supports method chaining for assertions.
|
|
//
|
|
// Example usage:
|
|
//
|
|
// testhelpers.GET(t, api, "/api/v1/query", "query", "up").
|
|
// ValidateOpenAPI().
|
|
// RequireSuccess().
|
|
// RequireEquals("$.data.resultType", "vector").
|
|
// RequireLenAtLeast("$.data.result", 1)
|
|
//
|
|
// testhelpers.POST(t, api, "/api/v1/query", "query", "up").
|
|
// ValidateOpenAPI().
|
|
// RequireSuccess().
|
|
// RequireArrayContains("$.data.result", expectedValue)
|
|
type Response struct {
|
|
StatusCode int
|
|
Body string
|
|
JSON map[string]any
|
|
t *testing.T
|
|
request *http.Request
|
|
requestBody []byte
|
|
responseHeader http.Header
|
|
}
|
|
|
|
// GET sends a GET request to the API and returns a Response with parsed JSON.
|
|
// queryParams should be pairs of key-value strings.
|
|
func GET(t *testing.T, api *APIWrapper, path string, queryParams ...string) *Response {
|
|
t.Helper()
|
|
|
|
if len(queryParams)%2 != 0 {
|
|
t.Fatal("queryParams must be key-value pairs")
|
|
}
|
|
|
|
// Build query string.
|
|
values := url.Values{}
|
|
for i := 0; i < len(queryParams); i += 2 {
|
|
values.Add(queryParams[i], queryParams[i+1])
|
|
}
|
|
|
|
fullPath := path
|
|
if len(values) > 0 {
|
|
fullPath = path + "?" + values.Encode()
|
|
}
|
|
|
|
req := httptest.NewRequest(http.MethodGet, fullPath, http.NoBody)
|
|
return executeRequest(t, api, req)
|
|
}
|
|
|
|
// POST sends a POST request to the API with the given body and returns a Response with parsed JSON.
|
|
// bodyParams should be pairs of key-value strings for form data.
|
|
func POST(t *testing.T, api *APIWrapper, path string, bodyParams ...string) *Response {
|
|
t.Helper()
|
|
|
|
if len(bodyParams)%2 != 0 {
|
|
t.Fatal("bodyParams must be key-value pairs")
|
|
}
|
|
|
|
// Build form data.
|
|
values := url.Values{}
|
|
for i := 0; i < len(bodyParams); i += 2 {
|
|
values.Add(bodyParams[i], bodyParams[i+1])
|
|
}
|
|
|
|
req := httptest.NewRequest(http.MethodPost, path, strings.NewReader(values.Encode()))
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
return executeRequest(t, api, req)
|
|
}
|
|
|
|
// executeRequest executes an HTTP request and parses the response as JSON.
|
|
func executeRequest(t *testing.T, api *APIWrapper, req *http.Request) *Response {
|
|
t.Helper()
|
|
|
|
// Capture the request body for validation.
|
|
var requestBody []byte
|
|
if req.Body != nil {
|
|
var err error
|
|
requestBody, err = io.ReadAll(req.Body)
|
|
if err != nil {
|
|
t.Fatalf("failed to read request body: %v", err)
|
|
}
|
|
// Restore the body for the actual request.
|
|
req.Body = io.NopCloser(strings.NewReader(string(requestBody)))
|
|
}
|
|
|
|
recorder := httptest.NewRecorder()
|
|
api.Handler.ServeHTTP(recorder, req)
|
|
|
|
result := recorder.Result()
|
|
defer result.Body.Close()
|
|
|
|
bodyBytes, err := io.ReadAll(result.Body)
|
|
if err != nil {
|
|
t.Fatalf("failed to read response body: %v", err)
|
|
}
|
|
|
|
resp := &Response{
|
|
StatusCode: result.StatusCode,
|
|
Body: string(bodyBytes),
|
|
t: t,
|
|
request: req,
|
|
requestBody: requestBody,
|
|
responseHeader: result.Header,
|
|
}
|
|
|
|
// Try to parse as JSON.
|
|
if result.Header.Get("Content-Type") == "application/json" || strings.Contains(result.Header.Get("Content-Type"), "application/json") {
|
|
var jsonData map[string]any
|
|
if err := json.Unmarshal(bodyBytes, &jsonData); err != nil {
|
|
// If JSON parsing fails, leave JSON as nil.
|
|
// This allows tests to handle non-JSON responses.
|
|
resp.JSON = nil
|
|
} else {
|
|
resp.JSON = jsonData
|
|
}
|
|
}
|
|
|
|
return resp
|
|
}
|