mirror of
https://github.com/hanzoai/traces.git
synced 2026-10-30 18:20:41 +00:00
* Update prometheus to latest release v2.47.1 (c4d1a8b) I ran ``` go get github.com/prometheus/prometheus@c4d1a8b ``` And fixed any compilation issues * Checkin .test files from prometheus * go mod tidy * More fixes * Final set of fixes? 🤞 * Lint --------- Co-authored-by: Mario <[email protected]>
265 lines
6.5 KiB
Go
265 lines
6.5 KiB
Go
package e2e
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"io"
|
|
"io/ioutil"
|
|
"math"
|
|
"math/rand"
|
|
"net/http"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/prometheus/common/model"
|
|
"github.com/prometheus/prometheus/model/labels"
|
|
"github.com/prometheus/prometheus/prompb"
|
|
)
|
|
|
|
func RunCommandAndGetOutput(name string, args ...string) ([]byte, error) {
|
|
cmd := exec.Command(name, args...)
|
|
return cmd.CombinedOutput()
|
|
}
|
|
|
|
func RunCommandWithTimeoutAndGetOutput(timeout time.Duration, name string, args ...string) ([]byte, error) {
|
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
|
defer cancel()
|
|
|
|
cmd := exec.CommandContext(ctx, name, args...)
|
|
return cmd.CombinedOutput()
|
|
}
|
|
|
|
func EmptyFlags() map[string]string {
|
|
return map[string]string{}
|
|
}
|
|
|
|
func MergeFlags(inputs ...map[string]string) map[string]string {
|
|
output := MergeFlagsWithoutRemovingEmpty(inputs...)
|
|
|
|
for k, v := range output {
|
|
if v == "" {
|
|
delete(output, k)
|
|
}
|
|
}
|
|
|
|
return output
|
|
}
|
|
|
|
func MergeFlagsWithoutRemovingEmpty(inputs ...map[string]string) map[string]string {
|
|
output := map[string]string{}
|
|
|
|
for _, input := range inputs {
|
|
for name, value := range input {
|
|
output[name] = value
|
|
}
|
|
}
|
|
|
|
return output
|
|
}
|
|
|
|
func BuildArgs(flags map[string]string) []string {
|
|
args := make([]string, 0, len(flags))
|
|
|
|
for name, value := range flags {
|
|
if value != "" {
|
|
args = append(args, name+"="+value)
|
|
} else {
|
|
args = append(args, name)
|
|
}
|
|
}
|
|
|
|
return args
|
|
}
|
|
|
|
// DoGet performs an HTTP GET request towards the supplied URL and using a
|
|
// timeout of 1 second.
|
|
func DoGet(url string) (*http.Response, error) {
|
|
return doRequestWithTimeout("GET", url, nil, nil, time.Second)
|
|
}
|
|
|
|
// DoGetWithTimeout performs an HTTP GET request towards the supplied URL and using a
|
|
// specified timeout.
|
|
func DoGetWithTimeout(url string, timeout time.Duration) (*http.Response, error) {
|
|
return doRequestWithTimeout("GET", url, nil, nil, timeout)
|
|
}
|
|
|
|
// DoGetTLS is like DoGet but allows to configure a TLS config.
|
|
func DoGetTLS(url string, tlsConfig *tls.Config) (*http.Response, error) {
|
|
return doRequestWithTimeout("GET", url, nil, tlsConfig, time.Second)
|
|
}
|
|
|
|
// DoPost performs a HTTP POST request towards the supplied URL with an empty
|
|
// body and using a timeout of 1 second.
|
|
func DoPost(url string) (*http.Response, error) {
|
|
return doRequestWithTimeout("POST", url, strings.NewReader(""), nil, time.Second)
|
|
}
|
|
|
|
func doRequestWithTimeout(method, url string, body io.Reader, tlsConfig *tls.Config, timeout time.Duration) (*http.Response, error) {
|
|
req, err := http.NewRequest(method, url, body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
client := &http.Client{
|
|
Timeout: timeout,
|
|
Transport: &http.Transport{
|
|
TLSClientConfig: tlsConfig,
|
|
},
|
|
}
|
|
|
|
return client.Do(req)
|
|
}
|
|
|
|
// TimeToMilliseconds returns the input time as milliseconds, using the same
|
|
// formula used by Prometheus in order to get the same timestamp when asserting
|
|
// on query results. The formula we're mimicking here is Prometheus parseTime().
|
|
// See: https://github.com/prometheus/prometheus/blob/df80dc4d3970121f2f76cba79050983ffb3cdbb0/web/api/v1/api.go#L1690-L1694
|
|
func TimeToMilliseconds(t time.Time) int64 {
|
|
// Convert to seconds.
|
|
sec := float64(t.Unix()) + float64(t.Nanosecond())/1e9
|
|
|
|
// Parse seconds.
|
|
s, ns := math.Modf(sec)
|
|
|
|
// Round nanoseconds part.
|
|
ns = math.Round(ns*1000) / 1000
|
|
|
|
// Convert to millis.
|
|
return (int64(s) * 1e3) + (int64(ns * 1e3))
|
|
}
|
|
|
|
func GenerateSeries(name string, ts time.Time, additionalLabels ...prompb.Label) (series []prompb.TimeSeries, vector model.Vector, matrix model.Matrix) {
|
|
tsMillis := TimeToMilliseconds(ts)
|
|
value := rand.Float64()
|
|
|
|
lbls := append(
|
|
[]prompb.Label{
|
|
{Name: labels.MetricName, Value: name},
|
|
},
|
|
additionalLabels...,
|
|
)
|
|
|
|
// Generate the series
|
|
series = append(series, prompb.TimeSeries{
|
|
Labels: lbls,
|
|
Exemplars: []prompb.Exemplar{
|
|
{Value: value, Timestamp: tsMillis, Labels: []prompb.Label{
|
|
{Name: "trace_id", Value: "1234"},
|
|
}},
|
|
},
|
|
Samples: []prompb.Sample{
|
|
{Value: value, Timestamp: tsMillis},
|
|
},
|
|
})
|
|
|
|
// Generate the expected vector and matrix when querying it
|
|
metric := model.Metric{}
|
|
metric[labels.MetricName] = model.LabelValue(name)
|
|
for _, lbl := range additionalLabels {
|
|
metric[model.LabelName(lbl.Name)] = model.LabelValue(lbl.Value)
|
|
}
|
|
|
|
vector = append(vector, &model.Sample{
|
|
Metric: metric,
|
|
Value: model.SampleValue(value),
|
|
Timestamp: model.Time(tsMillis),
|
|
})
|
|
|
|
matrix = append(matrix, &model.SampleStream{
|
|
Metric: metric,
|
|
Values: []model.SamplePair{
|
|
{
|
|
Timestamp: model.Time(tsMillis),
|
|
Value: model.SampleValue(value),
|
|
},
|
|
},
|
|
})
|
|
|
|
return
|
|
}
|
|
|
|
func GenerateNSeries(nSeries, nExemplars int, name func() string, ts time.Time, additionalLabels func() []prompb.Label) (series []prompb.TimeSeries, vector model.Vector) {
|
|
tsMillis := TimeToMilliseconds(ts)
|
|
|
|
// Generate the series
|
|
for i := 0; i < nSeries; i++ {
|
|
lbls := []prompb.Label{
|
|
{Name: labels.MetricName, Value: name()},
|
|
}
|
|
if additionalLabels != nil {
|
|
lbls = append(lbls, additionalLabels()...)
|
|
}
|
|
|
|
value := rand.Float64()
|
|
|
|
exemplars := []prompb.Exemplar{}
|
|
if i < nExemplars {
|
|
exemplars = []prompb.Exemplar{
|
|
{Value: value, Timestamp: tsMillis, Labels: []prompb.Label{{Name: "trace_id", Value: "1234"}}},
|
|
}
|
|
}
|
|
|
|
series = append(series, prompb.TimeSeries{
|
|
Labels: lbls,
|
|
Samples: []prompb.Sample{
|
|
{Value: value, Timestamp: tsMillis},
|
|
},
|
|
Exemplars: exemplars,
|
|
})
|
|
}
|
|
|
|
// Generate the expected vector when querying it
|
|
for i := 0; i < nSeries; i++ {
|
|
metric := model.Metric{}
|
|
for _, lbl := range series[i].Labels {
|
|
metric[model.LabelName(lbl.Name)] = model.LabelValue(lbl.Value)
|
|
}
|
|
|
|
vector = append(vector, &model.Sample{
|
|
Metric: metric,
|
|
Value: model.SampleValue(series[i].Samples[0].Value),
|
|
Timestamp: model.Time(tsMillis),
|
|
})
|
|
}
|
|
return
|
|
}
|
|
|
|
// GetTempDirectory creates a temporary directory for shared integration
|
|
// test files, either in the working directory or a directory referenced by
|
|
// the E2E_TEMP_DIR environment variable
|
|
func GetTempDirectory() (string, error) {
|
|
var (
|
|
dir string
|
|
err error
|
|
)
|
|
// If a temp dir is referenced, return that
|
|
if os.Getenv("E2E_TEMP_DIR") != "" {
|
|
dir = os.Getenv("E2E_TEMP_DIR")
|
|
} else {
|
|
dir, err = os.Getwd()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
}
|
|
|
|
tmpDir, err := ioutil.TempDir(dir, "e2e_integration_test")
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
// Allow use of the temporary directory for testing with non-root
|
|
// users.
|
|
if err := os.Chmod(tmpDir, 0777); err != nil {
|
|
return "", err
|
|
}
|
|
absDir, err := filepath.Abs(tmpDir)
|
|
if err != nil {
|
|
_ = os.RemoveAll(tmpDir)
|
|
return "", err
|
|
}
|
|
|
|
return absDir, nil
|
|
}
|