Merge remote-tracking branch 'upstream/main' into sparsehistogram

Signed-off-by: Ganesh Vernekar <ganeshvern@gmail.com>
This commit is contained in:
Ganesh Vernekar 2022-10-25 14:38:56 -04:00
commit e3719d670b
No known key found for this signature in database
GPG key ID: F056451B52F1DC34
8 changed files with 306 additions and 26 deletions

View file

@ -44,7 +44,7 @@ Release cadence of first pre-releases being cut is 6 weeks.
| v2.37 LTS | 2022-06-29 | Julien Pivotto (GitHub: @roidelapluie) |
| v2.38 | 2022-08-10 | Julius Volz (GitHub: @juliusv) |
| v2.39 | 2022-09-21 | Ganesh Vernekar (GitHub: @codesome) |
| v2.40 | 2022-11-02 | **searching for volunteer** |
| v2.40 | 2022-11-02 | Ganesh Vernekar (GitHub: @codesome) |
| v2.41 | 2022-12-14 | **searching for volunteer** |
If you are interested in volunteering please create a pull request against the [prometheus/prometheus](https://github.com/prometheus/prometheus) repository and propose yourself for the release series of your choice.

View file

@ -60,6 +60,8 @@ const (
datacenterLabel = model.MetaLabelPrefix + "consul_dc"
// namespaceLabel is the name of the label containing the namespace (Consul Enterprise only).
namespaceLabel = model.MetaLabelPrefix + "consul_namespace"
// partitionLabel is the name of the label containing the Admin Partition (Consul Enterprise only).
partitionLabel = model.MetaLabelPrefix + "consul_partition"
// taggedAddressesLabel is the prefix for the labels mapping to a target's tagged addresses.
taggedAddressesLabel = model.MetaLabelPrefix + "consul_tagged_address_"
// serviceIDLabel is the name of the label containing the service ID.
@ -112,6 +114,7 @@ type SDConfig struct {
Token config.Secret `yaml:"token,omitempty"`
Datacenter string `yaml:"datacenter,omitempty"`
Namespace string `yaml:"namespace,omitempty"`
Partition string `yaml:"partition,omitempty"`
TagSeparator string `yaml:"tag_separator,omitempty"`
Scheme string `yaml:"scheme,omitempty"`
Username string `yaml:"username,omitempty"`
@ -183,6 +186,7 @@ type Discovery struct {
client *consul.Client
clientDatacenter string
clientNamespace string
clientPartition string
tagSeparator string
watchedServices []string // Set of services which will be discovered.
watchedTags []string // Tags used to filter instances of a service.
@ -210,6 +214,7 @@ func NewDiscovery(conf *SDConfig, logger log.Logger) (*Discovery, error) {
Scheme: conf.Scheme,
Datacenter: conf.Datacenter,
Namespace: conf.Namespace,
Partition: conf.Partition,
Token: string(conf.Token),
HttpClient: wrapper,
}
@ -227,6 +232,7 @@ func NewDiscovery(conf *SDConfig, logger log.Logger) (*Discovery, error) {
refreshInterval: time.Duration(conf.RefreshInterval),
clientDatacenter: conf.Datacenter,
clientNamespace: conf.Namespace,
clientPartition: conf.Partition,
finalizer: wrapper.CloseIdleConnections,
logger: logger,
}
@ -547,6 +553,7 @@ func (srv *consulService) watch(ctx context.Context, ch chan<- []*targetgroup.Gr
addressLabel: model.LabelValue(serviceNode.Node.Address),
nodeLabel: model.LabelValue(serviceNode.Node.Node),
namespaceLabel: model.LabelValue(serviceNode.Service.Namespace),
partitionLabel: model.LabelValue(serviceNode.Service.Partition),
tagsLabel: model.LabelValue(tags),
serviceAddressLabel: model.LabelValue(serviceNode.Service.Address),
servicePortLabel: model.LabelValue(strconv.Itoa(serviceNode.Service.Port)),

View file

@ -518,6 +518,7 @@ The following meta labels are available on targets during [relabeling](#relabel_
* `__meta_consul_address`: the address of the target
* `__meta_consul_dc`: the datacenter name for the target
* `__meta_consul_health`: the health status of the service
* `__meta_consul_partition`: the admin partition name where the service is registered
* `__meta_consul_metadata_<key>`: each node metadata key value of the target
* `__meta_consul_node`: the node name defined for the target
* `__meta_consul_service_address`: the service address of the target
@ -536,6 +537,8 @@ The following meta labels are available on targets during [relabeling](#relabel_
[ datacenter: <string> ]
# Namespaces are only supported in Consul Enterprise.
[ namespace: <string> ]
# Admin Partitions are only supported in Consul Enterprise.
[ partition: <string> ]
[ scheme: <string> | default = "http" ]
# The username and password fields are deprecated in favor of the basic_auth configuration.
[ username: <string> ]
@ -2266,7 +2269,7 @@ tls_config:
### `<serverset_sd_config>`
Serverset SD configurations allow retrieving scrape targets from [Serversets]
(https://github.com/twitter/finagle/tree/master/finagle-serversets) which are
(https://github.com/twitter/finagle/tree/develop/finagle-serversets) which are
stored in [Zookeeper](https://zookeeper.apache.org/). Serversets are commonly
used by [Finagle](https://twitter.github.io/finagle/) and
[Aurora](https://aurora.apache.org/).

6
go.mod
View file

@ -11,7 +11,7 @@ require (
github.com/cespare/xxhash/v2 v2.1.2
github.com/dennwc/varint v1.0.0
github.com/dgryski/go-sip13 v0.0.0-20200911182023-62edffca9245
github.com/digitalocean/godo v1.84.1
github.com/digitalocean/godo v1.86.0
github.com/docker/docker v20.10.18+incompatible
github.com/edsrzf/mmap-go v1.1.0
github.com/envoyproxy/go-control-plane v0.10.3
@ -60,13 +60,13 @@ require (
go.uber.org/atomic v1.10.0
go.uber.org/automaxprocs v1.5.1
go.uber.org/goleak v1.2.0
golang.org/x/net v0.0.0-20220920203100-d0c6ba3f52d9
golang.org/x/net v0.0.0-20220921155015-db77216a4ee9
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1
golang.org/x/sync v0.0.0-20220907140024-f12130a52804
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8
golang.org/x/time v0.0.0-20220920022843-2ce7c2934d45
golang.org/x/tools v0.1.12
google.golang.org/api v0.96.0
google.golang.org/api v0.98.0
google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006
google.golang.org/grpc v1.49.0
google.golang.org/protobuf v1.28.1

12
go.sum
View file

@ -175,8 +175,8 @@ github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgz
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20200911182023-62edffca9245 h1:9cOfvEwjQxdwKuNDTQSaMKNRvwKwgZG+U4HrjeRKHso=
github.com/dgryski/go-sip13 v0.0.0-20200911182023-62edffca9245/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/digitalocean/godo v1.84.1 h1:VgPsuxhrO9pUygvij6qOhqXfAkxAsDZYRpmjSDMEaHo=
github.com/digitalocean/godo v1.84.1/go.mod h1:BPCqvwbjbGqxuUnIKB4EvS/AX7IDnNmt5fwvIkWo+ew=
github.com/digitalocean/godo v1.86.0 h1:GKB2HS+6lnYPn+9XLLsIVBWk3xk7v568EJnmdHuyhKA=
github.com/digitalocean/godo v1.86.0/go.mod h1:jELt1jkHVifd0rKaY0pt/m1QxGzbkkvoVVrDkR15/5A=
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
@ -1011,8 +1011,8 @@ golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220907135653-1e95f45603a7/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20220920203100-d0c6ba3f52d9 h1:asZqf0wXastQr+DudYagQS8uBO8bHKeYD1vbAvGmFL8=
golang.org/x/net v0.0.0-20220920203100-d0c6ba3f52d9/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20220921155015-db77216a4ee9 h1:SdDGdqRuKrF2R4XGcnPzcvZ63c/55GvhoHUus0o+BNI=
golang.org/x/net v0.0.0-20220921155015-db77216a4ee9/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -1281,8 +1281,8 @@ google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69
google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
google.golang.org/api v0.96.0 h1:F60cuQPJq7K7FzsxMYHAUJSiXh2oKctHxBMbDygxhfM=
google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
google.golang.org/api v0.98.0 h1:yxZrcxXESimy6r6mdL5Q6EnZwmewDJK2dVg3g75s5Dg=
google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=

View file

@ -553,12 +553,12 @@ func (api *API) queryExemplars(r *http.Request) apiFuncResult {
ctx := r.Context()
eq, err := api.ExemplarQueryable.ExemplarQuerier(ctx)
if err != nil {
return apiFuncResult{nil, &apiError{errorExec, err}, nil, nil}
return apiFuncResult{nil, returnAPIError(err), nil, nil}
}
res, err := eq.Select(timestamp.FromTime(start), timestamp.FromTime(end), selectors...)
if err != nil {
return apiFuncResult{nil, &apiError{errorExec, err}, nil, nil}
return apiFuncResult{nil, returnAPIError(err), nil, nil}
}
return apiFuncResult{res, nil, nil, nil}
@ -603,7 +603,7 @@ func (api *API) labelNames(r *http.Request) apiFuncResult {
q, err := api.Queryable.Querier(r.Context(), timestamp.FromTime(start), timestamp.FromTime(end))
if err != nil {
return apiFuncResult{nil, &apiError{errorExec, err}, nil, nil}
return apiFuncResult{nil, returnAPIError(err), nil, nil}
}
defer q.Close()
@ -617,7 +617,7 @@ func (api *API) labelNames(r *http.Request) apiFuncResult {
for _, matchers := range matcherSets {
vals, callWarnings, err := q.LabelNames(matchers...)
if err != nil {
return apiFuncResult{nil, &apiError{errorExec, err}, warnings, nil}
return apiFuncResult{nil, returnAPIError(err), warnings, nil}
}
warnings = append(warnings, callWarnings...)
@ -753,7 +753,7 @@ func (api *API) series(r *http.Request) (result apiFuncResult) {
q, err := api.Queryable.Querier(r.Context(), timestamp.FromTime(start), timestamp.FromTime(end))
if err != nil {
return apiFuncResult{nil, &apiError{errorExec, err}, nil, nil}
return apiFuncResult{nil, returnAPIError(err), nil, nil}
}
// From now on, we must only return with a finalizer in the result (to
// be called by the caller) or call q.Close ourselves (which is required
@ -794,7 +794,7 @@ func (api *API) series(r *http.Request) (result apiFuncResult) {
warnings := set.Warnings()
if set.Err() != nil {
return apiFuncResult{nil, &apiError{errorExec, set.Err()}, warnings, closer}
return apiFuncResult{nil, returnAPIError(set.Err()), warnings, closer}
}
return apiFuncResult{metrics, nil, warnings, closer}

View file

@ -31,6 +31,7 @@ import (
"time"
"github.com/prometheus/prometheus/model/histogram"
"github.com/prometheus/prometheus/prompb"
"github.com/prometheus/prometheus/util/stats"
"github.com/go-kit/log"
@ -47,7 +48,6 @@ import (
"github.com/prometheus/prometheus/model/labels"
"github.com/prometheus/prometheus/model/textparse"
"github.com/prometheus/prometheus/model/timestamp"
"github.com/prometheus/prometheus/prompb"
"github.com/prometheus/prometheus/promql"
"github.com/prometheus/prometheus/promql/parser"
"github.com/prometheus/prometheus/rules"
@ -453,7 +453,13 @@ func TestEndpoints(t *testing.T) {
})
}
func TestLabelNames(t *testing.T) {
type byLabels []labels.Labels
func (b byLabels) Len() int { return len(b) }
func (b byLabels) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
func (b byLabels) Less(i, j int) bool { return labels.Compare(b[i], b[j]) < 0 }
func TestGetSeries(t *testing.T) {
// TestEndpoints doesn't have enough label names to test api.labelNames
// endpoint properly. Hence we test it separately.
suite, err := promql.NewTest(t, `
@ -467,7 +473,6 @@ func TestLabelNames(t *testing.T) {
require.NoError(t, err)
defer suite.Close()
require.NoError(t, suite.Run())
api := &API{
Queryable: suite.Storage(),
}
@ -488,28 +493,286 @@ func TestLabelNames(t *testing.T) {
}
for _, tc := range []struct {
name string
matchers []string
expected []string
name string
api *API
matchers []string
expected []labels.Labels
expectedErrorType errorType
}{
{
name: "no matchers",
expectedErrorType: errorBadData,
api: api,
},
{
name: "non empty label matcher",
matchers: []string{`{foo=~".+"}`},
expected: []labels.Labels{
{labels.Label{Name: "__name__", Value: "test_metric2"}, labels.Label{Name: "abc", Value: "qwerty"}, labels.Label{Name: "foo", Value: "baz"}},
{labels.Label{Name: "__name__", Value: "test_metric2"}, labels.Label{Name: "foo", Value: "boo"}},
{labels.Label{Name: "__name__", Value: "test_metric2"}, labels.Label{Name: "foo", Value: "boo"}, labels.Label{Name: "xyz", Value: "qwerty"}},
},
api: api,
},
{
name: "exact label matcher",
matchers: []string{`{foo="boo"}`},
expected: []labels.Labels{
{labels.Label{Name: "__name__", Value: "test_metric2"}, labels.Label{Name: "foo", Value: "boo"}},
{labels.Label{Name: "__name__", Value: "test_metric2"}, labels.Label{Name: "foo", Value: "boo"}, labels.Label{Name: "xyz", Value: "qwerty"}},
},
api: api,
},
{
name: "two matchers",
matchers: []string{`{foo="boo"}`, `{foo="baz"}`},
expected: []labels.Labels{
{labels.Label{Name: "__name__", Value: "test_metric2"}, labels.Label{Name: "abc", Value: "qwerty"}, labels.Label{Name: "foo", Value: "baz"}},
{labels.Label{Name: "__name__", Value: "test_metric2"}, labels.Label{Name: "foo", Value: "boo"}},
{labels.Label{Name: "__name__", Value: "test_metric2"}, labels.Label{Name: "foo", Value: "boo"}, labels.Label{Name: "xyz", Value: "qwerty"}},
},
api: api,
},
{
name: "exec error type",
matchers: []string{`{foo="boo"}`, `{foo="baz"}`},
expectedErrorType: errorExec,
api: &API{
Queryable: errorTestQueryable{err: fmt.Errorf("generic")},
},
},
{
name: "storage error type",
matchers: []string{`{foo="boo"}`, `{foo="baz"}`},
expectedErrorType: errorInternal,
api: &API{
Queryable: errorTestQueryable{err: promql.ErrStorage{Err: fmt.Errorf("generic")}},
},
},
} {
t.Run(tc.name, func(t *testing.T) {
ctx := context.Background()
req, err := request(http.MethodGet, tc.matchers...)
require.NoError(t, err)
res := tc.api.series(req.WithContext(ctx))
assertAPIError(t, res.err, tc.expectedErrorType)
if tc.expectedErrorType == errorNone {
r := res.data.([]labels.Labels)
for _, l := range tc.expected {
sort.Sort(l)
}
for _, l := range r {
sort.Sort(l)
}
sort.Sort(byLabels(tc.expected))
sort.Sort(byLabels(r))
require.Equal(t, tc.expected, r)
}
})
}
}
func TestQueryExemplars(t *testing.T) {
start := time.Unix(0, 0)
suite, err := promql.NewTest(t, `
load 1m
test_metric1{foo="bar"} 0+100x100
test_metric1{foo="boo"} 1+0x100
test_metric2{foo="boo"} 1+0x100
test_metric3{foo="bar", dup="1"} 1+0x100
test_metric3{foo="boo", dup="1"} 1+0x100
test_metric4{foo="bar", dup="1"} 1+0x100
test_metric4{foo="boo", dup="1"} 1+0x100
test_metric4{foo="boo"} 1+0x100
`)
require.NoError(t, err)
defer suite.Close()
require.NoError(t, suite.Run())
api := &API{
Queryable: suite.Storage(),
QueryEngine: suite.QueryEngine(),
ExemplarQueryable: suite.ExemplarQueryable(),
}
request := func(method string, qs url.Values) (*http.Request, error) {
u, err := url.Parse("http://example.com")
require.NoError(t, err)
u.RawQuery = qs.Encode()
r, err := http.NewRequest(method, u.String(), nil)
if method == http.MethodPost {
r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
return r, err
}
for _, tc := range []struct {
name string
query url.Values
exemplars []exemplar.QueryResult
api *API
expectedErrorType errorType
}{
{
name: "no error",
api: api,
query: url.Values{
"query": []string{`test_metric3{foo="boo"} - test_metric4{foo="bar"}`},
"start": []string{"0"},
"end": []string{"4"},
},
exemplars: []exemplar.QueryResult{
{
SeriesLabels: labels.FromStrings("__name__", "test_metric3", "foo", "boo", "dup", "1"),
Exemplars: []exemplar.Exemplar{
{
Labels: labels.FromStrings("id", "abc"),
Value: 10,
Ts: timestamp.FromTime(start.Add(0 * time.Second)),
},
},
},
{
SeriesLabels: labels.FromStrings("__name__", "test_metric4", "foo", "bar", "dup", "1"),
Exemplars: []exemplar.Exemplar{
{
Labels: labels.FromStrings("id", "lul"),
Value: 10,
Ts: timestamp.FromTime(start.Add(3 * time.Second)),
},
},
},
},
},
{
name: "should return errorExec upon genetic error",
expectedErrorType: errorExec,
api: &API{
ExemplarQueryable: errorTestQueryable{err: fmt.Errorf("generic")},
},
query: url.Values{
"query": []string{`test_metric3{foo="boo"} - test_metric4{foo="bar"}`},
"start": []string{"0"},
"end": []string{"4"},
},
},
{
name: "should return errorInternal err type is ErrStorage",
expectedErrorType: errorInternal,
api: &API{
ExemplarQueryable: errorTestQueryable{err: promql.ErrStorage{Err: fmt.Errorf("generic")}},
},
query: url.Values{
"query": []string{`test_metric3{foo="boo"} - test_metric4{foo="bar"}`},
"start": []string{"0"},
"end": []string{"4"},
},
},
} {
t.Run(tc.name, func(t *testing.T) {
es := suite.ExemplarStorage()
ctx := context.Background()
for _, te := range tc.exemplars {
for _, e := range te.Exemplars {
_, err := es.AppendExemplar(0, te.SeriesLabels, e)
if err != nil {
t.Fatal(err)
}
}
}
req, err := request(http.MethodGet, tc.query)
require.NoError(t, err)
res := tc.api.queryExemplars(req.WithContext(ctx))
assertAPIError(t, res.err, tc.expectedErrorType)
if tc.expectedErrorType == errorNone {
assertAPIResponse(t, res.data, tc.exemplars)
}
})
}
}
func TestLabelNames(t *testing.T) {
// TestEndpoints doesn't have enough label names to test api.labelNames
// endpoint properly. Hence we test it separately.
suite, err := promql.NewTest(t, `
load 1m
test_metric1{foo1="bar", baz="abc"} 0+100x100
test_metric1{foo2="boo"} 1+0x100
test_metric2{foo="boo"} 1+0x100
test_metric2{foo="boo", xyz="qwerty"} 1+0x100
test_metric2{foo="baz", abc="qwerty"} 1+0x100
`)
require.NoError(t, err)
defer suite.Close()
require.NoError(t, suite.Run())
api := &API{
Queryable: suite.Storage(),
}
request := func(method string, matchers ...string) (*http.Request, error) {
u, err := url.Parse("http://example.com")
require.NoError(t, err)
q := u.Query()
for _, matcher := range matchers {
q.Add("match[]", matcher)
}
u.RawQuery = q.Encode()
r, err := http.NewRequest(method, u.String(), nil)
if method == http.MethodPost {
r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
return r, err
}
for _, tc := range []struct {
name string
api *API
matchers []string
expected []string
expectedErrorType errorType
}{
{
name: "no matchers",
expected: []string{"__name__", "abc", "baz", "foo", "foo1", "foo2", "xyz"},
api: api,
},
{
name: "non empty label matcher",
matchers: []string{`{foo=~".+"}`},
expected: []string{"__name__", "abc", "foo", "xyz"},
api: api,
},
{
name: "exact label matcher",
matchers: []string{`{foo="boo"}`},
expected: []string{"__name__", "foo", "xyz"},
api: api,
},
{
name: "two matchers",
matchers: []string{`{foo="boo"}`, `{foo="baz"}`},
expected: []string{"__name__", "abc", "foo", "xyz"},
api: api,
},
{
name: "exec error type",
matchers: []string{`{foo="boo"}`, `{foo="baz"}`},
expectedErrorType: errorExec,
api: &API{
Queryable: errorTestQueryable{err: fmt.Errorf("generic")},
},
},
{
name: "storage error type",
matchers: []string{`{foo="boo"}`, `{foo="baz"}`},
expectedErrorType: errorInternal,
api: &API{
Queryable: errorTestQueryable{err: promql.ErrStorage{Err: fmt.Errorf("generic")}},
},
},
} {
t.Run(tc.name, func(t *testing.T) {
@ -517,9 +780,11 @@ func TestLabelNames(t *testing.T) {
ctx := context.Background()
req, err := request(method, tc.matchers...)
require.NoError(t, err)
res := api.labelNames(req.WithContext(ctx))
assertAPIError(t, res.err, "")
assertAPIResponse(t, res.data, tc.expected)
res := tc.api.labelNames(req.WithContext(ctx))
assertAPIError(t, res.err, tc.expectedErrorType)
if tc.expectedErrorType == errorNone {
assertAPIResponse(t, res.data, tc.expected)
}
}
})
}

View file

@ -141,10 +141,15 @@ func createPrometheusAPI(q storage.SampleAndChunkQueryable) *route.Router {
}
type errorTestQueryable struct {
storage.ExemplarQueryable
q storage.Querier
err error
}
func (t errorTestQueryable) ExemplarQuerier(ctx context.Context) (storage.ExemplarQuerier, error) {
return nil, t.err
}
func (t errorTestQueryable) ChunkQuerier(ctx context.Context, mint, maxt int64) (storage.ChunkQuerier, error) {
return nil, t.err
}