The Prometheus monitoring system and time series database.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
prometheus/web/api/testhelpers/mocks.go

534 lines
14 KiB

// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This file contains mock implementations of API dependencies for testing.
package testhelpers
import (
"context"
"net/url"
"github.com/prometheus/prometheus/config"
"github.com/prometheus/prometheus/model/exemplar"
"github.com/prometheus/prometheus/model/histogram"
"github.com/prometheus/prometheus/model/labels"
"github.com/prometheus/prometheus/promql"
"github.com/prometheus/prometheus/rules"
"github.com/prometheus/prometheus/scrape"
"github.com/prometheus/prometheus/storage"
"github.com/prometheus/prometheus/tsdb"
"github.com/prometheus/prometheus/tsdb/chunkenc"
"github.com/prometheus/prometheus/tsdb/chunks"
"github.com/prometheus/prometheus/util/annotations"
)
// LazyLoader allows lazy initialization of mocks per test.
type LazyLoader[T any] struct {
loader func() T
value *T
}
// NewLazyLoader creates a new LazyLoader with the given loader function.
func NewLazyLoader[T any](loader func() T) *LazyLoader[T] {
return &LazyLoader[T]{loader: loader}
}
// Get returns the loaded value, initializing it if necessary.
func (l *LazyLoader[T]) Get() T {
if l.value == nil {
v := l.loader()
l.value = &v
}
return *l.value
}
// FakeQueryable implements storage.SampleAndChunkQueryable with configurable behavior.
type FakeQueryable struct {
series []storage.Series
}
func (f *FakeQueryable) Querier(_, _ int64) (storage.Querier, error) {
return &FakeQuerier{series: f.series}, nil
}
func (f *FakeQueryable) ChunkQuerier(_, _ int64) (storage.ChunkQuerier, error) {
return &FakeChunkQuerier{series: f.series}, nil
}
// FakeQuerier implements storage.Querier.
type FakeQuerier struct {
series []storage.Series
}
func (f *FakeQuerier) Select(_ context.Context, _ bool, _ *storage.SelectHints, _ ...*labels.Matcher) storage.SeriesSet {
return &FakeSeriesSet{series: f.series, idx: -1}
}
func (f *FakeQuerier) LabelValues(_ context.Context, name string, _ *storage.LabelHints, _ ...*labels.Matcher) ([]string, annotations.Annotations, error) {
valuesMap := make(map[string]struct{})
for _, s := range f.series {
lbls := s.Labels()
if val := lbls.Get(name); val != "" {
valuesMap[val] = struct{}{}
}
}
values := make([]string, 0, len(valuesMap))
for v := range valuesMap {
values = append(values, v)
}
return values, nil, nil
}
func (f *FakeQuerier) LabelNames(_ context.Context, _ *storage.LabelHints, _ ...*labels.Matcher) ([]string, annotations.Annotations, error) {
namesMap := make(map[string]struct{})
for _, s := range f.series {
lbls := s.Labels()
lbls.Range(func(l labels.Label) {
namesMap[l.Name] = struct{}{}
})
}
names := make([]string, 0, len(namesMap))
for n := range namesMap {
names = append(names, n)
}
return names, nil, nil
}
func (*FakeQuerier) Close() error {
return nil
}
// FakeChunkQuerier implements storage.ChunkQuerier.
type FakeChunkQuerier struct {
series []storage.Series
}
func (f *FakeChunkQuerier) Select(_ context.Context, _ bool, _ *storage.SelectHints, _ ...*labels.Matcher) storage.ChunkSeriesSet {
return &FakeChunkSeriesSet{series: f.series, idx: -1}
}
func (f *FakeChunkQuerier) LabelValues(_ context.Context, name string, _ *storage.LabelHints, _ ...*labels.Matcher) ([]string, annotations.Annotations, error) {
valuesMap := make(map[string]struct{})
for _, s := range f.series {
lbls := s.Labels()
if val := lbls.Get(name); val != "" {
valuesMap[val] = struct{}{}
}
}
values := make([]string, 0, len(valuesMap))
for v := range valuesMap {
values = append(values, v)
}
return values, nil, nil
}
func (f *FakeChunkQuerier) LabelNames(_ context.Context, _ *storage.LabelHints, _ ...*labels.Matcher) ([]string, annotations.Annotations, error) {
namesMap := make(map[string]struct{})
for _, s := range f.series {
lbls := s.Labels()
lbls.Range(func(l labels.Label) {
namesMap[l.Name] = struct{}{}
})
}
names := make([]string, 0, len(namesMap))
for n := range namesMap {
names = append(names, n)
}
return names, nil, nil
}
func (*FakeChunkQuerier) Close() error {
return nil
}
// FakeSeriesSet implements storage.SeriesSet.
type FakeSeriesSet struct {
series []storage.Series
idx int
}
func (f *FakeSeriesSet) Next() bool {
f.idx++
return f.idx < len(f.series)
}
func (f *FakeSeriesSet) At() storage.Series {
return f.series[f.idx]
}
func (*FakeSeriesSet) Err() error {
return nil
}
func (*FakeSeriesSet) Warnings() annotations.Annotations {
return nil
}
// FakeChunkSeriesSet implements storage.ChunkSeriesSet.
type FakeChunkSeriesSet struct {
series []storage.Series
idx int
}
func (f *FakeChunkSeriesSet) Next() bool {
f.idx++
return f.idx < len(f.series)
}
func (f *FakeChunkSeriesSet) At() storage.ChunkSeries {
return &FakeChunkSeries{series: f.series[f.idx]}
}
func (*FakeChunkSeriesSet) Err() error {
return nil
}
func (*FakeChunkSeriesSet) Warnings() annotations.Annotations {
return nil
}
// FakeChunkSeries implements storage.ChunkSeries.
type FakeChunkSeries struct {
series storage.Series
}
func (f *FakeChunkSeries) Labels() labels.Labels {
return f.series.Labels()
}
func (*FakeChunkSeries) Iterator(_ chunks.Iterator) chunks.Iterator {
return &FakeChunkSeriesIterator{}
}
// FakeChunkSeriesIterator implements chunks.Iterator.
type FakeChunkSeriesIterator struct{}
func (*FakeChunkSeriesIterator) Next() bool {
return false
}
func (*FakeChunkSeriesIterator) At() chunks.Meta {
return chunks.Meta{}
}
func (*FakeChunkSeriesIterator) Err() error {
return nil
}
// FakeSeries implements storage.Series.
type FakeSeries struct {
labels labels.Labels
samples []promql.FPoint
}
func (f *FakeSeries) Labels() labels.Labels {
return f.labels
}
func (f *FakeSeries) Iterator(chunkenc.Iterator) chunkenc.Iterator {
return &FakeSeriesIterator{samples: f.samples, idx: -1}
}
// FakeSeriesIterator implements chunkenc.Iterator.
type FakeSeriesIterator struct {
samples []promql.FPoint
idx int
}
func (f *FakeSeriesIterator) Next() chunkenc.ValueType {
f.idx++
if f.idx < len(f.samples) {
return chunkenc.ValFloat
}
return chunkenc.ValNone
}
func (f *FakeSeriesIterator) Seek(t int64) chunkenc.ValueType {
for f.idx < len(f.samples)-1 {
f.idx++
if f.samples[f.idx].T >= t {
return chunkenc.ValFloat
}
}
return chunkenc.ValNone
}
func (f *FakeSeriesIterator) At() (int64, float64) {
s := f.samples[f.idx]
return s.T, s.F
}
func (*FakeSeriesIterator) AtHistogram(*histogram.Histogram) (int64, *histogram.Histogram) {
panic("not implemented")
}
func (*FakeSeriesIterator) AtFloatHistogram(*histogram.FloatHistogram) (int64, *histogram.FloatHistogram) {
panic("not implemented")
}
func (f *FakeSeriesIterator) AtT() int64 {
return f.samples[f.idx].T
}
func (*FakeSeriesIterator) AtST() int64 {
return 0
}
func (*FakeSeriesIterator) Err() error {
return nil
}
// FakeHistogramSeries implements storage.Series for histogram data.
type FakeHistogramSeries struct {
labels labels.Labels
histograms []promql.HPoint
}
func (f *FakeHistogramSeries) Labels() labels.Labels {
return f.labels
}
func (f *FakeHistogramSeries) Iterator(chunkenc.Iterator) chunkenc.Iterator {
return &FakeHistogramSeriesIterator{histograms: f.histograms, idx: -1}
}
// FakeHistogramSeriesIterator implements chunkenc.Iterator for histogram data.
type FakeHistogramSeriesIterator struct {
histograms []promql.HPoint
idx int
}
func (f *FakeHistogramSeriesIterator) Next() chunkenc.ValueType {
f.idx++
if f.idx < len(f.histograms) {
return chunkenc.ValFloatHistogram
}
return chunkenc.ValNone
}
func (f *FakeHistogramSeriesIterator) Seek(t int64) chunkenc.ValueType {
for f.idx < len(f.histograms)-1 {
f.idx++
if f.histograms[f.idx].T >= t {
return chunkenc.ValFloatHistogram
}
}
return chunkenc.ValNone
}
func (*FakeHistogramSeriesIterator) At() (int64, float64) {
panic("not a float value")
}
func (*FakeHistogramSeriesIterator) AtHistogram(*histogram.Histogram) (int64, *histogram.Histogram) {
panic("not implemented")
}
func (f *FakeHistogramSeriesIterator) AtFloatHistogram(*histogram.FloatHistogram) (int64, *histogram.FloatHistogram) {
h := f.histograms[f.idx]
return h.T, h.H
}
func (f *FakeHistogramSeriesIterator) AtT() int64 {
return f.histograms[f.idx].T
}
func (*FakeHistogramSeriesIterator) AtST() int64 {
return 0
}
func (*FakeHistogramSeriesIterator) Err() error {
return nil
}
// FakeExemplarQueryable implements storage.ExemplarQueryable.
type FakeExemplarQueryable struct{}
func (*FakeExemplarQueryable) ExemplarQuerier(_ context.Context) (storage.ExemplarQuerier, error) {
return &FakeExemplarQuerier{}, nil
}
// FakeExemplarQuerier implements storage.ExemplarQuerier.
type FakeExemplarQuerier struct{}
func (*FakeExemplarQuerier) Select(_, _ int64, _ ...[]*labels.Matcher) ([]exemplar.QueryResult, error) {
return nil, nil
}
// FakeRulesRetriever implements v1.RulesRetriever.
type FakeRulesRetriever struct {
groups []*rules.Group
}
func (f *FakeRulesRetriever) RuleGroups() []*rules.Group {
return f.groups
}
func (f *FakeRulesRetriever) AlertingRules() []*rules.AlertingRule {
var alertingRules []*rules.AlertingRule
for _, g := range f.groups {
for _, r := range g.Rules() {
if ar, ok := r.(*rules.AlertingRule); ok {
alertingRules = append(alertingRules, ar)
}
}
}
return alertingRules
}
// FakeTargetRetriever implements v1.TargetRetriever.
type FakeTargetRetriever struct {
active map[string][]*scrape.Target
dropped map[string][]*scrape.Target
droppedCounts map[string]int
scrapeConfig map[string]*config.ScrapeConfig
}
func (f *FakeTargetRetriever) TargetsActive() map[string][]*scrape.Target {
if f.active == nil {
return make(map[string][]*scrape.Target)
}
return f.active
}
func (f *FakeTargetRetriever) TargetsDropped() map[string][]*scrape.Target {
if f.dropped == nil {
return make(map[string][]*scrape.Target)
}
return f.dropped
}
func (f *FakeTargetRetriever) TargetsDroppedCounts() map[string]int {
if f.droppedCounts == nil {
return make(map[string]int)
}
return f.droppedCounts
}
func (f *FakeTargetRetriever) ScrapePoolConfig(name string) (*config.ScrapeConfig, error) {
if f.scrapeConfig == nil {
return nil, nil
}
return f.scrapeConfig[name], nil
}
// FakeScrapePoolsRetriever implements v1.ScrapePoolsRetriever.
type FakeScrapePoolsRetriever struct {
pools []string
}
func (f *FakeScrapePoolsRetriever) ScrapePools() []string {
if f.pools == nil {
return []string{}
}
return f.pools
}
// FakeAlertmanagerRetriever implements v1.AlertmanagerRetriever.
type FakeAlertmanagerRetriever struct{}
func (*FakeAlertmanagerRetriever) Alertmanagers() []*url.URL {
return nil
}
func (*FakeAlertmanagerRetriever) DroppedAlertmanagers() []*url.URL {
return nil
}
// FakeTSDBAdminStats implements v1.TSDBAdminStats.
type FakeTSDBAdminStats struct{}
func (*FakeTSDBAdminStats) CleanTombstones() error {
return nil
}
func (*FakeTSDBAdminStats) Delete(_ context.Context, _, _ int64, _ ...*labels.Matcher) error {
return nil
}
func (*FakeTSDBAdminStats) Snapshot(_ string, _ bool) error {
return nil
}
func (*FakeTSDBAdminStats) Stats(_ string, _ int) (*tsdb.Stats, error) {
return &tsdb.Stats{}, nil
}
func (*FakeTSDBAdminStats) WALReplayStatus() (tsdb.WALReplayStatus, error) {
return tsdb.WALReplayStatus{}, nil
}
func (*FakeTSDBAdminStats) BlockMetas() ([]tsdb.BlockMeta, error) {
return []tsdb.BlockMeta{}, nil
}
// NewEmptyQueryable returns a queryable with no series.
func NewEmptyQueryable() storage.SampleAndChunkQueryable {
return &FakeQueryable{series: []storage.Series{}}
}
// NewQueryableWithSeries returns a queryable with the given series.
func NewQueryableWithSeries(series []storage.Series) storage.SampleAndChunkQueryable {
return &FakeQueryable{series: series}
}
// TSDBNotReadyQueryable implements storage.SampleAndChunkQueryable that returns tsdb.ErrNotReady.
type TSDBNotReadyQueryable struct{}
func (*TSDBNotReadyQueryable) Querier(_, _ int64) (storage.Querier, error) {
return nil, tsdb.ErrNotReady
}
func (*TSDBNotReadyQueryable) ChunkQuerier(_, _ int64) (storage.ChunkQuerier, error) {
return nil, tsdb.ErrNotReady
}
// NewTSDBNotReadyQueryable returns a queryable that always returns tsdb.ErrNotReady.
func NewTSDBNotReadyQueryable() storage.SampleAndChunkQueryable {
return &TSDBNotReadyQueryable{}
}
// NewEmptyExemplarQueryable returns an exemplar queryable with no exemplars.
func NewEmptyExemplarQueryable() storage.ExemplarQueryable {
return &FakeExemplarQueryable{}
}
// NewEmptyRulesRetriever returns a rules retriever with no rules.
func NewEmptyRulesRetriever() *FakeRulesRetriever {
return &FakeRulesRetriever{groups: []*rules.Group{}}
}
// NewRulesRetrieverWithGroups returns a rules retriever with the given groups.
func NewRulesRetrieverWithGroups(groups []*rules.Group) *FakeRulesRetriever {
return &FakeRulesRetriever{groups: groups}
}
// NewEmptyTargetRetriever returns a target retriever with no targets.
func NewEmptyTargetRetriever() *FakeTargetRetriever {
return &FakeTargetRetriever{}
}
// NewEmptyScrapePoolsRetriever returns a scrape pools retriever with no pools.
func NewEmptyScrapePoolsRetriever() *FakeScrapePoolsRetriever {
return &FakeScrapePoolsRetriever{pools: []string{}}
}
// NewEmptyAlertmanagerRetriever returns an alertmanager retriever with no alertmanagers.
func NewEmptyAlertmanagerRetriever() *FakeAlertmanagerRetriever {
return &FakeAlertmanagerRetriever{}
}
// NewEmptyTSDBAdminStats returns a TSDB admin stats with no-op implementations.
func NewEmptyTSDBAdminStats() *FakeTSDBAdminStats {
return &FakeTSDBAdminStats{}
}