Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added alert compliance test for Thanos #5315

Merged
merged 15 commits into from Jun 21, 2022
7 changes: 1 addition & 6 deletions go.mod
Expand Up @@ -23,7 +23,7 @@ require (
github.com/chromedp/chromedp v0.5.3
github.com/cortexproject/cortex v1.10.1-0.20211124141505-4e9fc3a2b5ab
github.com/davecgh/go-spew v1.1.1
github.com/efficientgo/e2e v0.11.2-0.20220224081107-b67f7b039363
github.com/efficientgo/e2e v0.12.1-0.20220429160159-c0641fd0b1e6
github.com/efficientgo/tools/core v0.0.0-20210829154005-c7bad8450208
github.com/efficientgo/tools/extkingpin v0.0.0-20210609125236-d73259166f20
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb
Expand Down Expand Up @@ -123,12 +123,9 @@ require (
github.com/aws/aws-sdk-go-v2/service/sts v1.14.0 // indirect
github.com/aws/smithy-go v1.10.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/containerd/cgroups v1.0.3 // indirect
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
github.com/dennwc/varint v1.0.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dimchansky/utfbom v1.1.1 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/edsrzf/mmap-go v1.1.0 // indirect
github.com/elastic/go-sysinfo v1.1.1 // indirect
Expand All @@ -150,7 +147,6 @@ require (
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee // indirect
github.com/gobwas/pool v0.2.0 // indirect
github.com/gobwas/ws v1.0.2 // indirect
github.com/godbus/dbus/v5 v5.0.6 // indirect
github.com/gogo/googleapis v1.4.0 // indirect
github.com/golang-jwt/jwt/v4 v4.0.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
Expand Down Expand Up @@ -179,7 +175,6 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mozillazg/go-httpheader v0.2.1 // indirect
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 // indirect
github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e // indirect
github.com/opentracing-contrib/go-stdlib v1.0.0 // indirect
github.com/prometheus/common/sigv4 v0.1.0 // indirect
Expand Down
8 changes: 2 additions & 6 deletions go.sum
Expand Up @@ -383,7 +383,6 @@ github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4S
github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU=
github.com/containerd/cgroups v1.0.3 h1:ADZftAkglvCiD44c77s5YmMqaP2pzVCFZvBmAlBdAP4=
github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
Expand Down Expand Up @@ -587,8 +586,8 @@ github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ=
github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q=
github.com/efficientgo/e2e v0.11.2-0.20220224081107-b67f7b039363 h1:wlimY9L7RuHjNugLWsYH1wFTpkonEc3rktYSLx8aXu0=
github.com/efficientgo/e2e v0.11.2-0.20220224081107-b67f7b039363/go.mod h1:vDnF4AAEZmO0mvyFIATeDJPFaSRM7ywaOnKd61zaSoE=
github.com/efficientgo/e2e v0.12.1-0.20220429160159-c0641fd0b1e6 h1:C12Pfi3esBESKKB8dEOdcLiQ6Xif0kruf8sxgAjHHeU=
github.com/efficientgo/e2e v0.12.1-0.20220429160159-c0641fd0b1e6/go.mod h1:xDHUyIqAWyVWU29Lf+BaZoavW7xAbDEvTwHWWI/3bhk=
github.com/efficientgo/tools/core v0.0.0-20210731122119-5d4a0645ce9a h1:Az9zRvQubUIHE+tHAm0gG7Dwge08V8Q/9uNSIFjFm+A=
github.com/efficientgo/tools/core v0.0.0-20210731122119-5d4a0645ce9a/go.mod h1:OmVcnJopJL8d3X3sSXTiypGoUSgFq1aDGmlrdi9dn/M=
github.com/efficientgo/tools/extkingpin v0.0.0-20210609125236-d73259166f20 h1:kM/ALyvAnTrwSB+nlKqoKaDnZbInp1YImZvW+gtHwc8=
Expand Down Expand Up @@ -836,11 +835,9 @@ github.com/gocql/gocql v0.0.0-20200526081602-cd04bd7f22a7/go.mod h1:DL0ekTmBSTdl
github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/godbus/dbus v0.0.0-20190402143921-271e53dc4968/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68FptL43tDKIq8FladmaTs3Xs7Z8=
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.6 h1:mkgN1ofwASrYnJ5W6U/BxG15eXXXjirgZc7CLqkcaro=
github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
Expand Down Expand Up @@ -1475,7 +1472,6 @@ github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/
github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc=
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
Expand Down
114 changes: 102 additions & 12 deletions test/e2e/compatibility_test.go
Expand Up @@ -4,6 +4,8 @@
package e2e_test

import (
"bytes"
"fmt"
"io/ioutil"
"os"
"path/filepath"
Expand All @@ -12,10 +14,16 @@ import (

"github.com/efficientgo/e2e"
e2edb "github.com/efficientgo/e2e/db"
common_cfg "github.com/prometheus/common/config"
"github.com/prometheus/prometheus/config"
"github.com/thanos-io/thanos/pkg/alert"
"github.com/thanos-io/thanos/pkg/httpconfig"
"github.com/thanos-io/thanos/pkg/testutil"
"github.com/thanos-io/thanos/test/e2e/e2ethanos"
)

// TestPromQLCompliance tests PromQL compatibility against https://github.com/prometheus/compliance/tree/main/promql.
// NOTE: This requires dockerization of compliance framework: https://github.com/prometheus/compliance/pull/46
// Test requires at least ~11m, so run this with `-test.timeout 9999m`.
func TestPromQLCompliance(t *testing.T) {
t.Skip("This is interactive test, it requires time to build up (scrape) the data. The data is also obtain from remote promlab servers.")
Expand All @@ -24,7 +32,7 @@ func TestPromQLCompliance(t *testing.T) {
testutil.Ok(t, err)
t.Cleanup(e.Close)

// Start separate receive + Querier.
// Start receive + Querier.
receiverRunnable, err := e2ethanos.NewIngestingReceiver(e, "receive")
testutil.Ok(t, err)
queryReceive := e2edb.NewThanosQuerier(e, "query_receive", []string{receiverRunnable.InternalEndpoint("grpc")})
Expand Down Expand Up @@ -53,7 +61,7 @@ scrape_configs:
))
testutil.Ok(t, e2e.StartAndWaitReady(prom))

// Start separate sidecar + Querier
// Start sidecar + Querier
sidecar := e2edb.NewThanosSidecar(e, "sidecar", prom, e2edb.WithImage("thanos"))
querySidecar := e2edb.NewThanosQuerier(e, "query_sidecar", []string{sidecar.InternalEndpoint("grpc")}, e2edb.WithImage("thanos"))
testutil.Ok(t, e2e.StartAndWaitReady(sidecar, querySidecar))
Expand All @@ -70,24 +78,28 @@ scrape_configs:

t.Run("receive", func(t *testing.T) {
testutil.Ok(t, ioutil.WriteFile(filepath.Join(compliance.Dir(), "receive.yaml"),
[]byte(promLabelsPromQLConfig(prom, queryReceive, []string{"prometheus", "receive", "tenant_id"})), os.ModePerm))
[]byte(promQLCompatConfig(prom, queryReceive, []string{"prometheus", "receive", "tenant_id"})), os.ModePerm))

stdout, stderr, err := compliance.Exec(e2e.NewCommand("/promql-compliance-tester", "-config-file", filepath.Join(compliance.InternalDir(), "receive.yaml")))
t.Log(stdout, stderr)
testutil.Ok(t, err)
testutil.Ok(t, compliance.Exec(e2e.NewCommand(
"/promql-compliance-tester",
"-config-file", filepath.Join(compliance.InternalDir(), "receive.yaml"),
"-config-file", "/promql-test-queries.yml",
)))
})
t.Run("sidecar", func(t *testing.T) {
testutil.Ok(t, ioutil.WriteFile(filepath.Join(compliance.Dir(), "sidecar.yaml"),
[]byte(promLabelsPromQLConfig(prom, querySidecar, []string{"prometheus"})), os.ModePerm))

stdout, stderr, err := compliance.Exec(e2e.NewCommand("/promql-compliance-tester", "-config-file", filepath.Join(compliance.InternalDir(), "sidecar.yaml")))
t.Log(stdout, stderr)
testutil.Ok(t, err)
[]byte(promQLCompatConfig(prom, querySidecar, []string{"prometheus"})), os.ModePerm))

testutil.Ok(t, compliance.Exec(e2e.NewCommand(
"/promql-compliance-tester",
"-config-file", filepath.Join(compliance.InternalDir(), "sidecar.yaml"),
"-config-file", "/promql-test-queries.yml",
)))
})
}

func promLabelsPromQLConfig(reference *e2edb.Prometheus, target e2e.Runnable, dropLabels []string) string {
// nolint (it's still used in skipped test).
func promQLCompatConfig(reference *e2edb.Prometheus, target e2e.Runnable, dropLabels []string) string {
return `reference_target_config:
query_url: 'http://` + reference.InternalEndpoint("http") + `'

Expand All @@ -105,3 +117,81 @@ query_tweaks:
return ret
}()
}

// nolint (it's still used in skipped test).
type alwaysReadyProbe struct{}

// nolint (it's still used in skipped test).
func (p alwaysReadyProbe) Ready(e2e.Runnable) error { return nil }

// TestAlertCompliance tests Alert compatibility against https://github.com/prometheus/compliance/blob/main/alert_generator.
// NOTE: This requires dockerization of compliance framework: https://github.com/prometheus/compliance/pull/46
func TestAlertCompliance_StatelessRuler(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be great to have another test case for TSDB ruler.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same code is used, but yes - you played with it? Do you have it rdy? (we could add in another PR)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have the code now. Happy to add it in another pr once this gets merged.

t.Skip("This is an interactive test, using https://github.com/prometheus/compliance/tree/main/alert_generator testing is not optimized for CI runs")

e, err := e2e.NewDockerEnvironment("alert_compatibility")
testutil.Ok(t, err)
t.Cleanup(e.Close)

// Start receive + Querier.
receive, err := e2ethanos.NewIngestingReceiver(e, "receive")
Copy link
Contributor

@yeya24 yeya24 May 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are using Thanos receiver in this case, the alerts will have the tenant label. If I remember correctly, the alerts compliance test requires the exact match of alerts labels. So maybe we need to configure the Querier to ignore the tenant label

testutil.Ok(t, err)
query := e2edb.NewThanosQuerier(e, "query_receive", []string{receive.InternalEndpoint("grpc")})

compliance := e.Runnable("alert_generator_compliance_tester").WithPorts(map[string]int{"http": 8080}).Init(e2e.StartOptions{
Image: "alert_generator_compliance_tester:latest",
// Batch job with HTTP port, we will start it with Exec, no need for readiness.
Readiness: alwaysReadyProbe{},
bwplotka marked this conversation as resolved.
Show resolved Hide resolved
Command: e2e.NewCommandWithoutEntrypoint("tail", "-f", "/dev/null"),
})
ruler := e2ethanos.NewStatelessRuler(e, "1", "rules", []alert.AlertmanagerConfig{
{
EndpointsConfig: httpconfig.EndpointsConfig{
StaticAddresses: []string{compliance.InternalEndpoint("http")},
Scheme: "http",
},
Timeout: amTimeout,
APIVersion: alert.APIv1,
},
}, []httpconfig.Config{
{
EndpointsConfig: httpconfig.EndpointsConfig{
StaticAddresses: []string{
query.InternalEndpoint("http"),
},
Scheme: "http",
},
},
}, []*config.RemoteWriteConfig{
{URL: &common_cfg.URL{URL: urlParse(t, e2ethanos.RemoteWriteEndpoint(receive.InternalEndpoint("remote-write")))}, Name: "thanos-receiver"},
})
testutil.Ok(t, e2e.StartAndWaitReady(receive, query, ruler, compliance))

// Pull rules.yaml:
{
var stdout bytes.Buffer
testutil.Ok(t, compliance.Exec(e2e.NewCommand("cat", "/rules.yaml"), e2e.WithExecOptionStdout(&stdout)))
testutil.Ok(t, os.MkdirAll(filepath.Join(ruler.Dir(), "rules"), os.ModePerm))
testutil.Ok(t, os.WriteFile(filepath.Join(ruler.Dir(), "rules", "rules.yaml"), stdout.Bytes(), os.ModePerm))
}

testutil.Ok(t, ioutil.WriteFile(filepath.Join(compliance.Dir(), "test-thanos.yaml"),
[]byte(alertCompatConfig(receive, query)), os.ModePerm))

fmt.Println(alertCompatConfig(receive, query))

testutil.Ok(t, compliance.Exec(e2e.NewCommand(
"/alert_generator_compliance_tester", "-config-file", filepath.Join(compliance.InternalDir(), "test-thanos.yaml")),
))
}

// nolint (it's still used in skipped test).
func alertCompatConfig(receive e2e.Runnable, query e2e.Runnable) string {
return `settings:
remote_write_url: '` + e2ethanos.RemoteWriteEndpoint(receive.InternalEndpoint("http")) + `'
query_base_url: 'http://` + query.InternalEndpoint("http") + `'
rules_and_alerts_api_base_url: 'http://` + query.InternalEndpoint("http") + `'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see stateless ruler being set as one endpoint of the Thanos Querier so I guess we cannot read anything from the Querier? Maybe we can use ruler's endpoint directly?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point!

alert_reception_server_port: 8080
alert_message_parser: default
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about making this similar to https://github.com/thanos-io/thanos/blob/main/test/e2e/e2ethanos/services.go#L1058?
My preference is that it is more readable, just like reading yaml directory.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind any, happy to change.

`
}
17 changes: 8 additions & 9 deletions test/e2e/e2ethanos/services.go
Expand Up @@ -560,32 +560,32 @@ func NewIngestingReceiver(e e2e.Environment, name string) (e2e.InstrumentedRunna
return receiver, nil
}

func NewTSDBRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.AlertmanagerConfig, queryCfg []httpconfig.Config) (e2e.InstrumentedRunnable, error) {
func NewTSDBRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.AlertmanagerConfig, queryCfg []httpconfig.Config) e2e.InstrumentedRunnable {
return newRuler(e, name, ruleSubDir, amCfg, queryCfg, nil)
}

func NewStatelessRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.AlertmanagerConfig, queryCfg []httpconfig.Config, remoteWriteCfg []*config.RemoteWriteConfig) (e2e.InstrumentedRunnable, error) {
func NewStatelessRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.AlertmanagerConfig, queryCfg []httpconfig.Config, remoteWriteCfg []*config.RemoteWriteConfig) e2e.InstrumentedRunnable {
return newRuler(e, name, ruleSubDir, amCfg, queryCfg, remoteWriteCfg)
}

func newRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.AlertmanagerConfig, queryCfg []httpconfig.Config, remoteWriteCfg []*config.RemoteWriteConfig) (e2e.InstrumentedRunnable, error) {
func newRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.AlertmanagerConfig, queryCfg []httpconfig.Config, remoteWriteCfg []*config.RemoteWriteConfig) e2e.InstrumentedRunnable {
dir := filepath.Join(e.SharedDir(), "data", "rule", name)
container := filepath.Join(ContainerSharedDir, "data", "rule", name)

if err := os.MkdirAll(dir, 0750); err != nil {
return nil, errors.Wrap(err, "create rule dir")
return e2e.NewErrInstrumentedRunnable(name, errors.Wrap(err, "create rule dir"))
}

amCfgBytes, err := yaml.Marshal(alert.AlertingConfig{
Alertmanagers: amCfg,
})
if err != nil {
return nil, errors.Wrapf(err, "generate am file: %v", amCfg)
return e2e.NewErrInstrumentedRunnable(name, errors.Wrapf(err, "generate am file: %v", amCfg))
}

queryCfgBytes, err := yaml.Marshal(queryCfg)
if err != nil {
return nil, errors.Wrapf(err, "generate query file: %v", queryCfg)
return e2e.NewErrInstrumentedRunnable(name, errors.Wrapf(err, "generate query file: %v", queryCfg))
}

ruleArgs := map[string]string{
Expand All @@ -609,12 +609,12 @@ func newRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.Alertman
RemoteWriteConfigs []*config.RemoteWriteConfig `yaml:"remote_write,omitempty"`
}{remoteWriteCfg})
if err != nil {
return nil, errors.Wrapf(err, "generate remote write config: %v", remoteWriteCfg)
return e2e.NewErrInstrumentedRunnable(name, errors.Wrapf(err, "generate remote write config: %v", remoteWriteCfg))
}
ruleArgs["--remote-write.config"] = string(rwCfgBytes)
}

ruler := NewService(e,
return NewService(e,
fmt.Sprintf("rule-%v", name),
DefaultImage(),
e2e.NewCommand("rule", e2e.BuildArgs(ruleArgs)...),
Expand All @@ -623,7 +623,6 @@ func newRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.Alertman
9091,
)

return ruler, nil
}

func NewAlertmanager(e e2e.Environment, name string) (e2e.InstrumentedRunnable, error) {
Expand Down
12 changes: 6 additions & 6 deletions test/e2e/metadata_api_test.go
Expand Up @@ -63,38 +63,38 @@ func TestMetadataAPI_Fanout(t *testing.T) {
var promMeta map[string][]metadatapb.Meta
// Wait metadata response to be ready as Prometheus gets metadata after scrape.
testutil.Ok(t, runutil.Retry(5*time.Second, ctx.Done(), func() error {
promMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, mustURLParse(t, "http://"+prom1.Endpoint("http")), "", -1)
promMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, urlParse(t, "http://"+prom1.Endpoint("http")), "", -1)
testutil.Ok(t, err)
if len(promMeta) > 0 {
return nil
}
return fmt.Errorf("empty metadata response from Prometheus")
}))

thanosMeta, err := promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, mustURLParse(t, "http://"+q.Endpoint("http")), "", -1)
thanosMeta, err := promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, urlParse(t, "http://"+q.Endpoint("http")), "", -1)
testutil.Ok(t, err)
testutil.Assert(t, len(thanosMeta) > 0, "got empty metadata response from Thanos")

// Metadata response from Prometheus and Thanos Querier should be the same after deduplication.
metadataEqual(t, thanosMeta, promMeta)

// We only expect to see one metadata returned.
thanosMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, mustURLParse(t, "http://"+q.Endpoint("http")), "", 1)
thanosMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, urlParse(t, "http://"+q.Endpoint("http")), "", 1)
testutil.Ok(t, err)
testutil.Equals(t, len(thanosMeta), 1)

// We only expect to see ten metadata returned.
thanosMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, mustURLParse(t, "http://"+q.Endpoint("http")), "", 10)
thanosMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, urlParse(t, "http://"+q.Endpoint("http")), "", 10)
testutil.Ok(t, err)
testutil.Equals(t, len(thanosMeta), 10)

// No metadata returned.
thanosMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, mustURLParse(t, "http://"+q.Endpoint("http")), "", 0)
thanosMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, urlParse(t, "http://"+q.Endpoint("http")), "", 0)
testutil.Ok(t, err)
testutil.Equals(t, len(thanosMeta), 0)

// Only prometheus_build_info metric will be returned.
thanosMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, mustURLParse(t, "http://"+q.Endpoint("http")), "prometheus_build_info", -1)
thanosMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, urlParse(t, "http://"+q.Endpoint("http")), "prometheus_build_info", -1)
testutil.Ok(t, err)
testutil.Assert(t, len(thanosMeta) == 1 && len(thanosMeta["prometheus_build_info"]) > 0, "expected one prometheus_build_info metadata from Thanos, got %v", thanosMeta)
}
Expand Down