github.com/netdata/go.d.plugin@v0.58.1/modules/prometheus/prometheus_test.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package prometheus
     4  
     5  import (
     6  	"fmt"
     7  	"net/http"
     8  	"net/http/httptest"
     9  	"testing"
    10  
    11  	"github.com/netdata/go.d.plugin/agent/module"
    12  	"github.com/netdata/go.d.plugin/pkg/prometheus/selector"
    13  	"github.com/netdata/go.d.plugin/pkg/web"
    14  
    15  	"github.com/stretchr/testify/assert"
    16  	"github.com/stretchr/testify/require"
    17  )
    18  
    19  func TestPrometheus_Init(t *testing.T) {
    20  	tests := map[string]struct {
    21  		config   Config
    22  		wantFail bool
    23  	}{
    24  		"non empty URL": {
    25  			wantFail: false,
    26  			config:   Config{HTTP: web.HTTP{Request: web.Request{URL: "http://127.0.0.1:9090/metric"}}},
    27  		},
    28  		"invalid selector syntax": {
    29  			wantFail: true,
    30  			config: Config{
    31  				HTTP:     web.HTTP{Request: web.Request{URL: "http://127.0.0.1:9090/metric"}},
    32  				Selector: selector.Expr{Allow: []string{`name{label=#"value"}`}},
    33  			},
    34  		},
    35  		"default": {
    36  			wantFail: true,
    37  			config:   New().Config,
    38  		},
    39  	}
    40  
    41  	for name, test := range tests {
    42  		t.Run(name, func(t *testing.T) {
    43  			prom := New()
    44  			prom.Config = test.config
    45  
    46  			if test.wantFail {
    47  				assert.False(t, prom.Init())
    48  			} else {
    49  				assert.True(t, prom.Init())
    50  			}
    51  		})
    52  	}
    53  }
    54  
    55  func TestPrometheus_Cleanup(t *testing.T) {
    56  	assert.NotPanics(t, New().Cleanup)
    57  
    58  	prom := New()
    59  	prom.URL = "http://127.0.0.1"
    60  	require.True(t, prom.Init())
    61  	assert.NotPanics(t, prom.Cleanup)
    62  }
    63  
    64  func TestPrometheus_Check(t *testing.T) {
    65  	tests := map[string]struct {
    66  		prepare  func() (prom *Prometheus, cleanup func())
    67  		wantFail bool
    68  	}{
    69  		"success if endpoint returns valid metrics in prometheus format": {
    70  			wantFail: false,
    71  			prepare: func() (prom *Prometheus, cleanup func()) {
    72  				srv := httptest.NewServer(http.HandlerFunc(
    73  					func(w http.ResponseWriter, r *http.Request) {
    74  						_, _ = w.Write([]byte(`test_counter_no_meta_metric_1_total{label1="value1"} 11`))
    75  					}))
    76  				prom = New()
    77  				prom.URL = srv.URL
    78  
    79  				return prom, srv.Close
    80  			},
    81  		},
    82  		"fail if the total num of metrics exceeds the limit": {
    83  			wantFail: true,
    84  			prepare: func() (prom *Prometheus, cleanup func()) {
    85  				srv := httptest.NewServer(http.HandlerFunc(
    86  					func(w http.ResponseWriter, r *http.Request) {
    87  						_, _ = w.Write([]byte(`
    88  test_counter_no_meta_metric_1_total{label1="value1"} 11
    89  test_counter_no_meta_metric_1_total{label1="value2"} 11
    90  `))
    91  					}))
    92  				prom = New()
    93  				prom.URL = srv.URL
    94  				prom.MaxTS = 1
    95  
    96  				return prom, srv.Close
    97  			},
    98  		},
    99  		"fail if the num time series in the metric exceeds the limit": {
   100  			wantFail: true,
   101  			prepare: func() (prom *Prometheus, cleanup func()) {
   102  				srv := httptest.NewServer(http.HandlerFunc(
   103  					func(w http.ResponseWriter, r *http.Request) {
   104  						_, _ = w.Write([]byte(`
   105  test_counter_no_meta_metric_1_total{label1="value1"} 11
   106  test_counter_no_meta_metric_1_total{label1="value2"} 11
   107  `))
   108  					}))
   109  				prom = New()
   110  				prom.URL = srv.URL
   111  				prom.MaxTSPerMetric = 1
   112  
   113  				return prom, srv.Close
   114  			},
   115  		},
   116  		"fail if metrics have no expected prefix": {
   117  			wantFail: true,
   118  			prepare: func() (prom *Prometheus, cleanup func()) {
   119  				srv := httptest.NewServer(http.HandlerFunc(
   120  					func(w http.ResponseWriter, r *http.Request) {
   121  						_, _ = w.Write([]byte(`test_counter_no_meta_metric_1_total{label1="value1"} 11`))
   122  					}))
   123  				prom = New()
   124  				prom.URL = srv.URL
   125  				prom.ExpectedPrefix = "prefix_"
   126  
   127  				return prom, srv.Close
   128  			},
   129  		},
   130  		"fail if endpoint returns data not in prometheus format": {
   131  			wantFail: true,
   132  			prepare: func() (prom *Prometheus, cleanup func()) {
   133  				srv := httptest.NewServer(http.HandlerFunc(
   134  					func(w http.ResponseWriter, r *http.Request) {
   135  						_, _ = w.Write([]byte("hello and\n goodbye"))
   136  					}))
   137  				prom = New()
   138  				prom.URL = srv.URL
   139  
   140  				return prom, srv.Close
   141  			},
   142  		},
   143  		"fail if connection refused": {
   144  			wantFail: true,
   145  			prepare: func() (prom *Prometheus, cleanup func()) {
   146  				prom = New()
   147  				prom.URL = "http://127.0.0.1:38001/metrics"
   148  
   149  				return prom, func() {}
   150  			},
   151  		},
   152  		"fail if endpoint returns 404": {
   153  			wantFail: true,
   154  			prepare: func() (prom *Prometheus, cleanup func()) {
   155  				srv := httptest.NewServer(http.HandlerFunc(
   156  					func(w http.ResponseWriter, r *http.Request) {
   157  						w.WriteHeader(http.StatusNotFound)
   158  					}))
   159  				prom = New()
   160  				prom.URL = srv.URL
   161  
   162  				return prom, srv.Close
   163  			},
   164  		},
   165  	}
   166  
   167  	for name, test := range tests {
   168  		t.Run(name, func(t *testing.T) {
   169  			prom, cleanup := test.prepare()
   170  			defer cleanup()
   171  
   172  			require.True(t, prom.Init())
   173  
   174  			if test.wantFail {
   175  				assert.False(t, prom.Check())
   176  			} else {
   177  				assert.True(t, prom.Check())
   178  			}
   179  		})
   180  	}
   181  }
   182  
   183  func TestPrometheus_Collect(t *testing.T) {
   184  	type testCaseStep struct {
   185  		desc          string
   186  		input         string
   187  		wantCollected map[string]int64
   188  		wantCharts    int
   189  	}
   190  	tests := map[string]struct {
   191  		prepare func() *Prometheus
   192  		steps   []testCaseStep
   193  	}{
   194  		"Gauge": {
   195  			prepare: New,
   196  			steps: []testCaseStep{
   197  				{
   198  					desc: "Two first seen series, no meta series ignored",
   199  					input: `
   200  # HELP test_gauge_metric_1 Test Gauge Metric 1
   201  # TYPE test_gauge_metric_1 gauge
   202  test_gauge_metric_1{label1="value1"} 11
   203  test_gauge_metric_1{label1="value2"} 12
   204  test_gauge_no_meta_metric_1{label1="value1"} 11
   205  test_gauge_no_meta_metric_1{label1="value2"} 12
   206  `,
   207  					wantCollected: map[string]int64{
   208  						"test_gauge_metric_1-label1=value1": 11000,
   209  						"test_gauge_metric_1-label1=value2": 12000,
   210  					},
   211  					wantCharts: 2,
   212  				},
   213  				{
   214  					desc: "One series removed",
   215  					input: `
   216  # HELP test_gauge_metric_1 Test Gauge Metric 1
   217  # TYPE test_gauge_metric_1 gauge
   218  test_gauge_metric_1{label1="value1"} 11
   219  `,
   220  					wantCollected: map[string]int64{
   221  						"test_gauge_metric_1-label1=value1": 11000,
   222  					},
   223  					wantCharts: 1,
   224  				},
   225  				{
   226  					desc: "One series (re)added",
   227  					input: `
   228  # HELP test_gauge_metric_1 Test Gauge Metric 1
   229  # TYPE test_gauge_metric_1 gauge
   230  test_gauge_metric_1{label1="value1"} 11
   231  test_gauge_metric_1{label1="value2"} 12
   232  `,
   233  					wantCollected: map[string]int64{
   234  						"test_gauge_metric_1-label1=value1": 11000,
   235  						"test_gauge_metric_1-label1=value2": 12000,
   236  					},
   237  					wantCharts: 2,
   238  				},
   239  			},
   240  		},
   241  		"Counter": {
   242  			prepare: New,
   243  			steps: []testCaseStep{
   244  				{
   245  					desc: "Four first seen series, no meta series collected",
   246  					input: `
   247  # HELP test_counter_metric_1_total Test Counter Metric 1
   248  # TYPE test_counter_metric_1_total counter
   249  test_counter_metric_1_total{label1="value1"} 11
   250  test_counter_metric_1_total{label1="value2"} 12
   251  test_counter_no_meta_metric_1_total{label1="value1"} 11
   252  test_counter_no_meta_metric_1_total{label1="value2"} 12
   253  `,
   254  					wantCollected: map[string]int64{
   255  						"test_counter_metric_1_total-label1=value1":         11000,
   256  						"test_counter_metric_1_total-label1=value2":         12000,
   257  						"test_counter_no_meta_metric_1_total-label1=value1": 11000,
   258  						"test_counter_no_meta_metric_1_total-label1=value2": 12000,
   259  					},
   260  					wantCharts: 4,
   261  				},
   262  				{
   263  					desc: "Two series removed",
   264  					input: `
   265  # HELP test_counter_metric_1_total Test Counter Metric 1
   266  # TYPE test_counter_metric_1_total counter
   267  test_counter_metric_1_total{label1="value1"} 11
   268  test_counter_no_meta_metric_1_total{label1="value1"} 11
   269  `,
   270  					wantCollected: map[string]int64{
   271  						"test_counter_metric_1_total-label1=value1":         11000,
   272  						"test_counter_no_meta_metric_1_total-label1=value1": 11000,
   273  					},
   274  					wantCharts: 2,
   275  				},
   276  				{
   277  					desc: "Two series (re)added",
   278  					input: `
   279  # HELP test_counter_metric_1_total Test Counter Metric 1
   280  # TYPE test_counter_metric_1_total counter
   281  test_counter_metric_1_total{label1="value1"} 11
   282  test_counter_metric_1_total{label1="value2"} 12
   283  test_counter_no_meta_metric_1_total{label1="value1"} 11
   284  test_counter_no_meta_metric_1_total{label1="value2"} 12
   285  `,
   286  					wantCollected: map[string]int64{
   287  						"test_counter_metric_1_total-label1=value1":         11000,
   288  						"test_counter_metric_1_total-label1=value2":         12000,
   289  						"test_counter_no_meta_metric_1_total-label1=value1": 11000,
   290  						"test_counter_no_meta_metric_1_total-label1=value2": 12000,
   291  					},
   292  					wantCharts: 4,
   293  				},
   294  			},
   295  		},
   296  		"Summary": {
   297  			prepare: New,
   298  			steps: []testCaseStep{
   299  				{
   300  					desc: "Two first seen series, no meta series collected",
   301  					input: `
   302  # HELP test_summary_1_duration_microseconds Test Summary Metric 1
   303  # TYPE test_summary_1_duration_microseconds summary
   304  test_summary_1_duration_microseconds{label1="value1",quantile="0.5"} 4931.921
   305  test_summary_1_duration_microseconds{label1="value1",quantile="0.9"} 4932.921
   306  test_summary_1_duration_microseconds{label1="value1",quantile="0.99"} 4933.921
   307  test_summary_1_duration_microseconds_sum{label1="value1"} 283201.29
   308  test_summary_1_duration_microseconds_count{label1="value1"} 31
   309  test_summary_no_meta_1_duration_microseconds{label1="value1",quantile="0.5"} 4931.921
   310  test_summary_no_meta_1_duration_microseconds{label1="value1",quantile="0.9"} 4932.921
   311  test_summary_no_meta_1_duration_microseconds{label1="value1",quantile="0.99"} 4933.921
   312  test_summary_no_meta_1_duration_microseconds_sum{label1="value1"} 283201.29
   313  test_summary_no_meta_1_duration_microseconds_count{label1="value1"} 31
   314  `,
   315  					wantCollected: map[string]int64{
   316  						"test_summary_1_duration_microseconds-label1=value1_count":                 31,
   317  						"test_summary_1_duration_microseconds-label1=value1_quantile=0.5":          4931921000,
   318  						"test_summary_1_duration_microseconds-label1=value1_quantile=0.9":          4932921000,
   319  						"test_summary_1_duration_microseconds-label1=value1_quantile=0.99":         4933921000,
   320  						"test_summary_1_duration_microseconds-label1=value1_sum":                   283201290,
   321  						"test_summary_no_meta_1_duration_microseconds-label1=value1_count":         31,
   322  						"test_summary_no_meta_1_duration_microseconds-label1=value1_quantile=0.5":  4931921000,
   323  						"test_summary_no_meta_1_duration_microseconds-label1=value1_quantile=0.9":  4932921000,
   324  						"test_summary_no_meta_1_duration_microseconds-label1=value1_quantile=0.99": 4933921000,
   325  						"test_summary_no_meta_1_duration_microseconds-label1=value1_sum":           283201290,
   326  					},
   327  					wantCharts: 6,
   328  				},
   329  				{
   330  					desc: "One series removed",
   331  					input: `
   332  # HELP test_summary_1_duration_microseconds Test Summary Metric 1
   333  # TYPE test_summary_1_duration_microseconds summary
   334  test_summary_1_duration_microseconds{label1="value1",quantile="0.5"} 4931.921
   335  test_summary_1_duration_microseconds{label1="value1",quantile="0.9"} 4932.921
   336  test_summary_1_duration_microseconds{label1="value1",quantile="0.99"} 4933.921
   337  test_summary_1_duration_microseconds_sum{label1="value1"} 283201.29
   338  test_summary_1_duration_microseconds_count{label1="value1"} 31
   339  `,
   340  					wantCollected: map[string]int64{
   341  						"test_summary_1_duration_microseconds-label1=value1_count":         31,
   342  						"test_summary_1_duration_microseconds-label1=value1_quantile=0.5":  4931921000,
   343  						"test_summary_1_duration_microseconds-label1=value1_quantile=0.9":  4932921000,
   344  						"test_summary_1_duration_microseconds-label1=value1_quantile=0.99": 4933921000,
   345  						"test_summary_1_duration_microseconds-label1=value1_sum":           283201290,
   346  					},
   347  					wantCharts: 3,
   348  				},
   349  				{
   350  					desc: "One series (re)added",
   351  					input: `
   352  # HELP test_summary_1_duration_microseconds Test Summary Metric 1
   353  # TYPE test_summary_1_duration_microseconds summary
   354  test_summary_1_duration_microseconds{label1="value1",quantile="0.5"} 4931.921
   355  test_summary_1_duration_microseconds{label1="value1",quantile="0.9"} 4932.921
   356  test_summary_1_duration_microseconds{label1="value1",quantile="0.99"} 4933.921
   357  test_summary_1_duration_microseconds_sum{label1="value1"} 283201.29
   358  test_summary_1_duration_microseconds_count{label1="value1"} 31
   359  test_summary_no_meta_1_duration_microseconds{label1="value1",quantile="0.5"} 4931.921
   360  test_summary_no_meta_1_duration_microseconds{label1="value1",quantile="0.9"} 4932.921
   361  test_summary_no_meta_1_duration_microseconds{label1="value1",quantile="0.99"} 4933.921
   362  test_summary_no_meta_1_duration_microseconds_sum{label1="value1"} 283201.29
   363  test_summary_no_meta_1_duration_microseconds_count{label1="value1"} 31
   364  `,
   365  					wantCollected: map[string]int64{
   366  						"test_summary_1_duration_microseconds-label1=value1_count":                 31,
   367  						"test_summary_1_duration_microseconds-label1=value1_quantile=0.5":          4931921000,
   368  						"test_summary_1_duration_microseconds-label1=value1_quantile=0.9":          4932921000,
   369  						"test_summary_1_duration_microseconds-label1=value1_quantile=0.99":         4933921000,
   370  						"test_summary_1_duration_microseconds-label1=value1_sum":                   283201290,
   371  						"test_summary_no_meta_1_duration_microseconds-label1=value1_count":         31,
   372  						"test_summary_no_meta_1_duration_microseconds-label1=value1_quantile=0.5":  4931921000,
   373  						"test_summary_no_meta_1_duration_microseconds-label1=value1_quantile=0.9":  4932921000,
   374  						"test_summary_no_meta_1_duration_microseconds-label1=value1_quantile=0.99": 4933921000,
   375  						"test_summary_no_meta_1_duration_microseconds-label1=value1_sum":           283201290,
   376  					},
   377  					wantCharts: 6,
   378  				},
   379  			},
   380  		},
   381  		"Summary with NaN": {
   382  			prepare: New,
   383  			steps: []testCaseStep{
   384  				{
   385  					desc: "Two first seen series, no meta series collected",
   386  					input: `
   387  # HELP test_summary_1_duration_microseconds Test Summary Metric 1
   388  # TYPE test_summary_1_duration_microseconds summary
   389  test_summary_1_duration_microseconds{label1="value1",quantile="0.5"} NaN
   390  test_summary_1_duration_microseconds{label1="value1",quantile="0.9"} NaN
   391  test_summary_1_duration_microseconds{label1="value1",quantile="0.99"} NaN
   392  test_summary_1_duration_microseconds_sum{label1="value1"} 283201.29
   393  test_summary_1_duration_microseconds_count{label1="value1"} 31
   394  test_summary_no_meta_1_duration_microseconds{label1="value1",quantile="0.5"} NaN
   395  test_summary_no_meta_1_duration_microseconds{label1="value1",quantile="0.9"} NaN
   396  test_summary_no_meta_1_duration_microseconds{label1="value1",quantile="0.99"} NaN
   397  test_summary_no_meta_1_duration_microseconds_sum{label1="value1"} 283201.29
   398  test_summary_no_meta_1_duration_microseconds_count{label1="value1"} 31
   399  `,
   400  					wantCollected: map[string]int64{
   401  						"test_summary_1_duration_microseconds-label1=value1_count":         31,
   402  						"test_summary_1_duration_microseconds-label1=value1_sum":           283201290,
   403  						"test_summary_no_meta_1_duration_microseconds-label1=value1_count": 31,
   404  						"test_summary_no_meta_1_duration_microseconds-label1=value1_sum":   283201290,
   405  					},
   406  					wantCharts: 6,
   407  				},
   408  			},
   409  		},
   410  		"Histogram": {
   411  			prepare: New,
   412  			steps: []testCaseStep{
   413  				{
   414  					desc: "Two first seen series, no meta series collected",
   415  					input: `
   416  # HELP test_histogram_1_duration_seconds Test Histogram Metric 1
   417  # TYPE test_histogram_1_duration_seconds histogram
   418  test_histogram_1_duration_seconds_bucket{label1="value1",le="0.1"} 4
   419  test_histogram_1_duration_seconds_bucket{label1="value1",le="0.5"} 5
   420  test_histogram_1_duration_seconds_bucket{label1="value1",le="+Inf"} 6
   421  test_histogram_1_duration_seconds_sum{label1="value1"} 0.00147889
   422  test_histogram_1_duration_seconds_count{label1="value1"} 6
   423  test_histogram_no_meta_1_duration_seconds_bucket{label1="value1",le="0.1"} 4
   424  test_histogram_no_meta_1_duration_seconds_bucket{label1="value1",le="0.5"} 5
   425  test_histogram_no_meta_1_duration_seconds_bucket{label1="value1",le="+Inf"} 6
   426  test_histogram_no_meta_1_duration_seconds_sum{label1="value1"} 0.00147889
   427  test_histogram_no_meta_1_duration_seconds_count{label1="value1"} 6
   428  `,
   429  					wantCollected: map[string]int64{
   430  						"test_histogram_1_duration_seconds-label1=value1_bucket=+Inf":         6,
   431  						"test_histogram_1_duration_seconds-label1=value1_bucket=0.1":          4,
   432  						"test_histogram_1_duration_seconds-label1=value1_bucket=0.5":          5,
   433  						"test_histogram_1_duration_seconds-label1=value1_count":               6,
   434  						"test_histogram_1_duration_seconds-label1=value1_sum":                 1,
   435  						"test_histogram_no_meta_1_duration_seconds-label1=value1_bucket=+Inf": 6,
   436  						"test_histogram_no_meta_1_duration_seconds-label1=value1_bucket=0.1":  4,
   437  						"test_histogram_no_meta_1_duration_seconds-label1=value1_bucket=0.5":  5,
   438  						"test_histogram_no_meta_1_duration_seconds-label1=value1_count":       6,
   439  						"test_histogram_no_meta_1_duration_seconds-label1=value1_sum":         1,
   440  					},
   441  					wantCharts: 6,
   442  				},
   443  				{
   444  					desc: "One series removed",
   445  					input: `
   446  # HELP test_histogram_1_duration_seconds Test Histogram Metric 1
   447  # TYPE test_histogram_1_duration_seconds histogram
   448  test_histogram_1_duration_seconds_bucket{label1="value1",le="0.1"} 4
   449  test_histogram_1_duration_seconds_bucket{label1="value1",le="0.5"} 5
   450  test_histogram_1_duration_seconds_bucket{label1="value1",le="+Inf"} 6
   451  `,
   452  					wantCollected: map[string]int64{
   453  						"test_histogram_1_duration_seconds-label1=value1_bucket=+Inf": 6,
   454  						"test_histogram_1_duration_seconds-label1=value1_bucket=0.1":  4,
   455  						"test_histogram_1_duration_seconds-label1=value1_bucket=0.5":  5,
   456  						"test_histogram_1_duration_seconds-label1=value1_count":       0,
   457  						"test_histogram_1_duration_seconds-label1=value1_sum":         0,
   458  					},
   459  					wantCharts: 3,
   460  				},
   461  				{
   462  					desc: "One series (re)added",
   463  					input: `
   464  # HELP test_histogram_1_duration_seconds Test Histogram Metric 1
   465  # TYPE test_histogram_1_duration_seconds histogram
   466  test_histogram_1_duration_seconds_bucket{label1="value1",le="0.1"} 4
   467  test_histogram_1_duration_seconds_bucket{label1="value1",le="0.5"} 5
   468  test_histogram_1_duration_seconds_bucket{label1="value1",le="+Inf"} 6
   469  test_histogram_1_duration_seconds_sum{label1="value1"} 0.00147889
   470  test_histogram_1_duration_seconds_count{label1="value1"} 6
   471  test_histogram_no_meta_1_duration_seconds_bucket{label1="value1",le="0.1"} 4
   472  test_histogram_no_meta_1_duration_seconds_bucket{label1="value1",le="0.5"} 5
   473  test_histogram_no_meta_1_duration_seconds_bucket{label1="value1",le="+Inf"} 6
   474  test_histogram_no_meta_1_duration_seconds_sum{label1="value1"} 0.00147889
   475  test_histogram_no_meta_1_duration_seconds_count{label1="value1"} 6
   476  `,
   477  					wantCollected: map[string]int64{
   478  						"test_histogram_1_duration_seconds-label1=value1_bucket=+Inf":         6,
   479  						"test_histogram_1_duration_seconds-label1=value1_bucket=0.1":          4,
   480  						"test_histogram_1_duration_seconds-label1=value1_bucket=0.5":          5,
   481  						"test_histogram_1_duration_seconds-label1=value1_count":               6,
   482  						"test_histogram_1_duration_seconds-label1=value1_sum":                 1,
   483  						"test_histogram_no_meta_1_duration_seconds-label1=value1_bucket=+Inf": 6,
   484  						"test_histogram_no_meta_1_duration_seconds-label1=value1_bucket=0.1":  4,
   485  						"test_histogram_no_meta_1_duration_seconds-label1=value1_bucket=0.5":  5,
   486  						"test_histogram_no_meta_1_duration_seconds-label1=value1_count":       6,
   487  						"test_histogram_no_meta_1_duration_seconds-label1=value1_sum":         1,
   488  					},
   489  					wantCharts: 6,
   490  				},
   491  			},
   492  		},
   493  		"match Untyped as Gauge": {
   494  			prepare: func() *Prometheus {
   495  				prom := New()
   496  				prom.FallbackType.Gauge = []string{"test_gauge_no_meta*"}
   497  				return prom
   498  			},
   499  			steps: []testCaseStep{
   500  				{
   501  					desc: "Two first seen series, meta series processed as Gauge",
   502  					input: `
   503  # HELP test_gauge_metric_1 Test Untyped Metric 1
   504  # TYPE test_gauge_metric_1 gauge
   505  test_gauge_metric_1{label1="value1"} 11
   506  test_gauge_metric_1{label1="value2"} 12
   507  test_gauge_no_meta_metric_1{label1="value1"} 11
   508  test_gauge_no_meta_metric_1{label1="value2"} 12
   509  `,
   510  					wantCollected: map[string]int64{
   511  						"test_gauge_metric_1-label1=value1":         11000,
   512  						"test_gauge_metric_1-label1=value2":         12000,
   513  						"test_gauge_no_meta_metric_1-label1=value1": 11000,
   514  						"test_gauge_no_meta_metric_1-label1=value2": 12000,
   515  					},
   516  					wantCharts: 4,
   517  				},
   518  			},
   519  		},
   520  		"match Untyped as Counter": {
   521  			prepare: func() *Prometheus {
   522  				prom := New()
   523  				prom.FallbackType.Counter = []string{"test_gauge_no_meta*"}
   524  				return prom
   525  			},
   526  			steps: []testCaseStep{
   527  				{
   528  					desc: "Two first seen series, meta series processed as Counter",
   529  					input: `
   530  # HELP test_gauge_metric_1 Test Untyped Metric 1
   531  # TYPE test_gauge_metric_1 gauge
   532  test_gauge_metric_1{label1="value1"} 11
   533  test_gauge_metric_1{label1="value2"} 12
   534  test_gauge_no_meta_metric_1{label1="value1"} 11
   535  test_gauge_no_meta_metric_1{label1="value2"} 12
   536  `,
   537  					wantCollected: map[string]int64{
   538  						"test_gauge_metric_1-label1=value1":         11000,
   539  						"test_gauge_metric_1-label1=value2":         12000,
   540  						"test_gauge_no_meta_metric_1-label1=value1": 11000,
   541  						"test_gauge_no_meta_metric_1-label1=value2": 12000,
   542  					},
   543  					wantCharts: 4,
   544  				},
   545  			},
   546  		},
   547  	}
   548  
   549  	for name, test := range tests {
   550  		t.Run(name, func(t *testing.T) {
   551  			prom := test.prepare()
   552  
   553  			var metrics []byte
   554  			srv := httptest.NewServer(http.HandlerFunc(
   555  				func(w http.ResponseWriter, r *http.Request) {
   556  					_, _ = w.Write(metrics)
   557  				}))
   558  			defer srv.Close()
   559  
   560  			prom.URL = srv.URL
   561  			require.True(t, prom.Init())
   562  
   563  			for num, step := range test.steps {
   564  				t.Run(fmt.Sprintf("step num %d ('%s')", num+1, step.desc), func(t *testing.T) {
   565  
   566  					metrics = []byte(step.input)
   567  
   568  					var mx map[string]int64
   569  
   570  					for i := 0; i < maxNotSeenTimes+1; i++ {
   571  						mx = prom.Collect()
   572  					}
   573  
   574  					assert.Equal(t, step.wantCollected, mx)
   575  					removeObsoleteCharts(prom.Charts())
   576  					assert.Len(t, *prom.Charts(), step.wantCharts)
   577  				})
   578  			}
   579  		})
   580  	}
   581  }
   582  
   583  func removeObsoleteCharts(charts *module.Charts) {
   584  	var i int
   585  	for _, chart := range *charts {
   586  		if !chart.Obsolete {
   587  			(*charts)[i] = chart
   588  			i++
   589  		}
   590  	}
   591  	*charts = (*charts)[:i]
   592  }