github.com/thanos-io/thanos@v0.32.5/test/e2e/metadata_api_test.go (about) 1 // Copyright (c) The Thanos Authors. 2 // Licensed under the Apache License 2.0. 3 4 package e2e_test 5 6 import ( 7 "context" 8 "fmt" 9 "sort" 10 "testing" 11 "time" 12 13 "github.com/efficientgo/e2e" 14 e2emon "github.com/efficientgo/e2e/monitoring" 15 16 "github.com/efficientgo/core/testutil" 17 "github.com/thanos-io/thanos/pkg/metadata/metadatapb" 18 "github.com/thanos-io/thanos/pkg/promclient" 19 "github.com/thanos-io/thanos/pkg/runutil" 20 "github.com/thanos-io/thanos/test/e2e/e2ethanos" 21 ) 22 23 func TestMetadataAPI_Fanout(t *testing.T) { 24 t.Parallel() 25 26 e, err := e2e.NewDockerEnvironment("metadata-fanout") 27 testutil.Ok(t, err) 28 t.Cleanup(e2ethanos.CleanScenario(t, e)) 29 30 // 2x Prometheus. 31 // Each Prometheus scrapes its own metrics and Sidecar's metrics. 32 prom1, sidecar1 := e2ethanos.NewPrometheusWithSidecar( 33 e, 34 "prom1", 35 e2ethanos.DefaultPromConfig("ha", 0, "", "", e2ethanos.LocalPrometheusTarget, "sidecar-prom1:8080"), 36 "", 37 e2ethanos.DefaultPrometheusImage(), "", 38 ) 39 prom2, sidecar2 := e2ethanos.NewPrometheusWithSidecar( 40 e, 41 "prom2", 42 e2ethanos.DefaultPromConfig("ha", 1, "", "", e2ethanos.LocalPrometheusTarget, "sidecar-prom2:8080"), 43 "", 44 e2ethanos.DefaultPrometheusImage(), "", 45 ) 46 testutil.Ok(t, e2e.StartAndWaitReady(prom1, sidecar1, prom2, sidecar2)) 47 48 stores := []string{sidecar1.InternalEndpoint("grpc"), sidecar2.InternalEndpoint("grpc")} 49 q := e2ethanos.NewQuerierBuilder( 50 e, "query", stores...). 51 WithMetadataAddresses(stores...). 52 Init() 53 testutil.Ok(t, e2e.StartAndWaitReady(q)) 54 55 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) 56 t.Cleanup(cancel) 57 58 testutil.Ok(t, q.WaitSumMetricsWithOptions(e2emon.Equals(2), []string{"thanos_store_nodes_grpc_connections"}, e2emon.WaitMissingMetrics())) 59 testutil.Ok(t, q.WaitSumMetricsWithOptions(e2emon.Equals(2), []string{"thanos_query_metadata_apis_dns_provider_results"}, e2emon.WaitMissingMetrics())) 60 61 var promMeta map[string][]metadatapb.Meta 62 // Wait metadata response to be ready as Prometheus gets metadata after scrape. 63 testutil.Ok(t, runutil.Retry(5*time.Second, ctx.Done(), func() error { 64 promMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, urlParse(t, "http://"+prom1.Endpoint("http")), "", -1) 65 if err != nil { 66 return err 67 } 68 if len(promMeta) > 0 { 69 return nil 70 } 71 return fmt.Errorf("empty metadata response from Prometheus") 72 })) 73 74 var thanosMeta map[string][]metadatapb.Meta 75 // Retry until length of metadata response is the same as Prometheus. 76 testutil.Ok(t, runutil.Retry(5*time.Second, ctx.Done(), func() error { 77 thanosMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, urlParse(t, "http://"+q.Endpoint("http")), "", -1) 78 if err != nil { 79 return err 80 } 81 if len(thanosMeta) == len(promMeta) { 82 return nil 83 } 84 85 return fmt.Errorf("different metadata response from Prometheus") 86 })) 87 88 testutil.Assert(t, len(thanosMeta) > 0, "got empty metadata response from Thanos") 89 90 // Metadata response from Prometheus and Thanos Querier should be the same after deduplication. 91 metadataEqual(t, thanosMeta, promMeta) 92 93 // We only expect to see one metadata returned. 94 thanosMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, urlParse(t, "http://"+q.Endpoint("http")), "", 1) 95 testutil.Ok(t, err) 96 testutil.Equals(t, len(thanosMeta), 1) 97 98 // We only expect to see ten metadata returned. 99 thanosMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, urlParse(t, "http://"+q.Endpoint("http")), "", 10) 100 testutil.Ok(t, err) 101 testutil.Equals(t, len(thanosMeta), 10) 102 103 // No metadata returned. 104 thanosMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, urlParse(t, "http://"+q.Endpoint("http")), "", 0) 105 testutil.Ok(t, err) 106 testutil.Equals(t, len(thanosMeta), 0) 107 108 // Only prometheus_build_info metric will be returned. 109 thanosMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, urlParse(t, "http://"+q.Endpoint("http")), "prometheus_build_info", -1) 110 testutil.Ok(t, err) 111 testutil.Assert(t, len(thanosMeta) == 1 && len(thanosMeta["prometheus_build_info"]) > 0, "expected one prometheus_build_info metadata from Thanos, got %v", thanosMeta) 112 } 113 114 func metadataEqual(t *testing.T, meta1, meta2 map[string][]metadatapb.Meta) { 115 // The two responses should have equal # of entries. 116 testutil.Equals(t, len(meta1), len(meta2)) 117 118 for metric := range meta1 { 119 // Get metadata for the metric. 120 meta1MetricMeta := meta1[metric] 121 meta2MetricMeta, ok := meta2[metric] 122 testutil.Assert(t, ok) 123 124 sort.Slice(meta1MetricMeta, func(i, j int) bool { 125 return meta1MetricMeta[i].Help < meta1MetricMeta[j].Help 126 }) 127 sort.Slice(meta2MetricMeta, func(i, j int) bool { 128 return meta2MetricMeta[i].Help < meta2MetricMeta[j].Help 129 }) 130 testutil.Equals(t, meta1MetricMeta, meta2MetricMeta) 131 } 132 }