mirror of
https://github.com/prometheus/prometheus.git
synced 2025-08-07 06:37:17 +02:00
test(cmd): add test for GOGC setting
As suggested in https://github.com/prometheus/prometheus/pull/14176#issuecomment-2150308054 Signed-off-by: machine424 <ayoubmrini424@gmail.com>
This commit is contained in:
parent
7e49b91d9a
commit
ca70ed4fed
@ -20,6 +20,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -33,6 +34,7 @@ import (
|
|||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/common/expfmt"
|
||||||
"github.com/prometheus/common/model"
|
"github.com/prometheus/common/model"
|
||||||
"github.com/prometheus/common/promslog"
|
"github.com/prometheus/common/promslog"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@ -41,6 +43,7 @@ import (
|
|||||||
"github.com/prometheus/prometheus/model/labels"
|
"github.com/prometheus/prometheus/model/labels"
|
||||||
"github.com/prometheus/prometheus/notifier"
|
"github.com/prometheus/prometheus/notifier"
|
||||||
"github.com/prometheus/prometheus/rules"
|
"github.com/prometheus/prometheus/rules"
|
||||||
|
"github.com/prometheus/prometheus/util/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -646,3 +649,120 @@ func TestRwProtoMsgFlagParser(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getGaugeValue(t *testing.T, body io.ReadCloser, metricName string) (float64, error) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
p := expfmt.TextParser{}
|
||||||
|
metricFamilies, err := p.TextToMetricFamilies(body)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
metricFamily, ok := metricFamilies[metricName]
|
||||||
|
if !ok {
|
||||||
|
return 0, errors.New("metric family not found")
|
||||||
|
}
|
||||||
|
metric := metricFamily.GetMetric()
|
||||||
|
if len(metric) != 1 {
|
||||||
|
return 0, errors.New("metric not found")
|
||||||
|
}
|
||||||
|
return metric[0].GetGauge().GetValue(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRuntimeGOGCConfig(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("skipping test in short mode.")
|
||||||
|
}
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
for _, tc := range []struct {
|
||||||
|
name string
|
||||||
|
config string
|
||||||
|
gogcEnvVar string
|
||||||
|
expectedGOGC int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty config file",
|
||||||
|
expectedGOGC: 75,
|
||||||
|
},
|
||||||
|
// the GOGC env var is ignored in this case, see https://github.com/prometheus/prometheus/issues/16334
|
||||||
|
/* {
|
||||||
|
name: "empty config file with GOGC env var set",
|
||||||
|
gogcEnvVar: "66",
|
||||||
|
expectedGOGC: 66,
|
||||||
|
}, */
|
||||||
|
{
|
||||||
|
name: "gogc set through config",
|
||||||
|
config: `
|
||||||
|
runtime:
|
||||||
|
gogc: 77`,
|
||||||
|
expectedGOGC: 77,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "gogc set through config and env var",
|
||||||
|
config: `
|
||||||
|
runtime:
|
||||||
|
gogc: 77`,
|
||||||
|
gogcEnvVar: "88",
|
||||||
|
expectedGOGC: 77,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "incomplete runtime block",
|
||||||
|
config: `
|
||||||
|
runtime:`,
|
||||||
|
expectedGOGC: 75,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "incomplete runtime block and GOGC env var set",
|
||||||
|
config: `
|
||||||
|
runtime:`,
|
||||||
|
gogcEnvVar: "88",
|
||||||
|
expectedGOGC: 88,
|
||||||
|
},
|
||||||
|
// the GOGC env var is ignored in this case, see https://github.com/prometheus/prometheus/issues/16334
|
||||||
|
/* {
|
||||||
|
name: "unrelated config and GOGC env var set",
|
||||||
|
config: `
|
||||||
|
global:
|
||||||
|
scrape_interval: 500ms`,
|
||||||
|
gogcEnvVar: "80",
|
||||||
|
expectedGOGC: 80,
|
||||||
|
}, */
|
||||||
|
} {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
configFile := filepath.Join(tmpDir, "prometheus.yml")
|
||||||
|
|
||||||
|
port := testutil.RandomUnprivilegedPort(t)
|
||||||
|
os.WriteFile(configFile, []byte(tc.config), 0o777)
|
||||||
|
prom := prometheusCommandWithLogging(t, configFile, port, fmt.Sprintf("--storage.tsdb.path=%s", tmpDir))
|
||||||
|
// Inject GOGC when set.
|
||||||
|
prom.Env = os.Environ()
|
||||||
|
if tc.gogcEnvVar != "" {
|
||||||
|
prom.Env = append(prom.Env, fmt.Sprintf("GOGC=%s", tc.gogcEnvVar))
|
||||||
|
}
|
||||||
|
require.NoError(t, prom.Start())
|
||||||
|
|
||||||
|
var (
|
||||||
|
r *http.Response
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
// Wait for the /metrics endpoint to be ready.
|
||||||
|
require.Eventually(t, func() bool {
|
||||||
|
r, err = http.Get(fmt.Sprintf("http://127.0.0.1:%d/metrics", port))
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return r.StatusCode == http.StatusOK
|
||||||
|
}, 5*time.Second, 50*time.Millisecond)
|
||||||
|
defer r.Body.Close()
|
||||||
|
|
||||||
|
// Check the final GOGC that's set, consider go_gc_gogc_percent from /metrics as source of truth.
|
||||||
|
gogc, err := getGaugeValue(t, r.Body, "go_gc_gogc_percent")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, float64(tc.expectedGOGC), gogc)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -119,7 +119,8 @@ func runTestSteps(t *testing.T, steps []struct {
|
|||||||
require.NoError(t, os.WriteFile(configFilePath, []byte(steps[0].configText), 0o644), "Failed to write initial config file")
|
require.NoError(t, os.WriteFile(configFilePath, []byte(steps[0].configText), 0o644), "Failed to write initial config file")
|
||||||
|
|
||||||
port := testutil.RandomUnprivilegedPort(t)
|
port := testutil.RandomUnprivilegedPort(t)
|
||||||
runPrometheusWithLogging(t, configFilePath, port)
|
prom := prometheusCommandWithLogging(t, configFilePath, port, "--enable-feature=auto-reload-config", "--config.auto-reload-interval=1s")
|
||||||
|
require.NoError(t, prom.Start())
|
||||||
|
|
||||||
baseURL := "http://localhost:" + strconv.Itoa(port)
|
baseURL := "http://localhost:" + strconv.Itoa(port)
|
||||||
require.Eventually(t, func() bool {
|
require.Eventually(t, func() bool {
|
||||||
@ -197,14 +198,20 @@ func captureLogsToTLog(t *testing.T, r io.Reader) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runPrometheusWithLogging(t *testing.T, configFilePath string, port int) {
|
func prometheusCommandWithLogging(t *testing.T, configFilePath string, port int, extraArgs ...string) *exec.Cmd {
|
||||||
stdoutPipe, stdoutWriter := io.Pipe()
|
stdoutPipe, stdoutWriter := io.Pipe()
|
||||||
stderrPipe, stderrWriter := io.Pipe()
|
stderrPipe, stderrWriter := io.Pipe()
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(2)
|
wg.Add(2)
|
||||||
|
|
||||||
prom := exec.Command(promPath, "-test.main", "--enable-feature=auto-reload-config", "--config.file="+configFilePath, "--config.auto-reload-interval=1s", "--web.listen-address=0.0.0.0:"+strconv.Itoa(port))
|
args := []string{
|
||||||
|
"-test.main",
|
||||||
|
"--config.file=" + configFilePath,
|
||||||
|
"--web.listen-address=0.0.0.0:" + strconv.Itoa(port),
|
||||||
|
}
|
||||||
|
args = append(args, extraArgs...)
|
||||||
|
prom := exec.Command(promPath, args...)
|
||||||
prom.Stdout = stdoutWriter
|
prom.Stdout = stdoutWriter
|
||||||
prom.Stderr = stderrWriter
|
prom.Stderr = stderrWriter
|
||||||
|
|
||||||
@ -224,6 +231,5 @@ func runPrometheusWithLogging(t *testing.T, configFilePath string, port int) {
|
|||||||
stderrWriter.Close()
|
stderrWriter.Close()
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
})
|
})
|
||||||
|
return prom
|
||||||
require.NoError(t, prom.Start())
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user