github.com/prebid/prebid-server/v2@v2.18.0/metrics/prometheus/prometheus_test.go (about)

     1  package prometheusmetrics
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/prebid/prebid-server/v2/config"
     9  	"github.com/prebid/prebid-server/v2/metrics"
    10  	"github.com/prebid/prebid-server/v2/openrtb_ext"
    11  	"github.com/prometheus/client_golang/prometheus"
    12  	dto "github.com/prometheus/client_model/go"
    13  	"github.com/stretchr/testify/assert"
    14  )
    15  
    16  var modulesStages = map[string][]string{"foobar": {"entry", "raw"}, "another_module": {"raw", "auction"}}
    17  
    18  func createMetricsForTesting() *Metrics {
    19  	syncerKeys := []string{}
    20  	return NewMetrics(config.PrometheusMetrics{
    21  		Port:      8080,
    22  		Namespace: "prebid",
    23  		Subsystem: "server",
    24  	}, config.DisabledMetrics{}, syncerKeys, modulesStages)
    25  }
    26  
    27  func TestMetricCountGatekeeping(t *testing.T) {
    28  	m := createMetricsForTesting()
    29  
    30  	// Gather All Metrics
    31  	metricFamilies, err := m.Gatherer.Gather()
    32  	assert.NoError(t, err, "gather metics")
    33  
    34  	// Summarize By Adapter Cardinality
    35  	// - This requires metrics to be preloaded. We don't preload account metrics, so we can't test those.
    36  	generalCardinalityCount := 0
    37  	adapterCardinalityCount := 0
    38  	for _, metricFamily := range metricFamilies {
    39  		for _, metric := range metricFamily.GetMetric() {
    40  			isPerAdapter := false
    41  			for _, label := range metric.GetLabel() {
    42  				if label.GetName() == adapterLabel {
    43  					isPerAdapter = true
    44  				}
    45  			}
    46  
    47  			if isPerAdapter {
    48  				adapterCardinalityCount++
    49  			} else {
    50  				generalCardinalityCount++
    51  			}
    52  		}
    53  	}
    54  
    55  	// Calculate Per-Adapter Cardinality
    56  	adapterCount := len(openrtb_ext.CoreBidderNames())
    57  	perAdapterCardinalityCount := adapterCardinalityCount / adapterCount
    58  	// Verify General Cardinality
    59  	// - This assertion provides a warning for newly added high-cardinality non-adapter specific metrics. The hardcoded limit
    60  	//   is an arbitrary soft ceiling. Thought should be given as to the value of the new metrics if you find yourself
    61  	//   needing to increase this number.
    62  	assert.True(t, generalCardinalityCount <= 500, "General Cardinality")
    63  
    64  	// Verify Per-Adapter Cardinality
    65  	// - This assertion provides a warning for newly added adapter metrics. Threre are 40+ adapters which makes the
    66  	//   cost of new per-adapter metrics rather expensive. Thought should be given when adding new per-adapter metrics.
    67  	assert.True(t, perAdapterCardinalityCount <= 31, "Per-Adapter Cardinality count equals %d \n", perAdapterCardinalityCount)
    68  }
    69  
    70  func TestConnectionMetrics(t *testing.T) {
    71  	testCases := []struct {
    72  		description              string
    73  		testCase                 func(m *Metrics)
    74  		expectedOpenedCount      float64
    75  		expectedOpenedErrorCount float64
    76  		expectedClosedCount      float64
    77  		expectedClosedErrorCount float64
    78  	}{
    79  		{
    80  			description: "Open Success",
    81  			testCase: func(m *Metrics) {
    82  				m.RecordConnectionAccept(true)
    83  			},
    84  			expectedOpenedCount:      1,
    85  			expectedOpenedErrorCount: 0,
    86  			expectedClosedCount:      0,
    87  			expectedClosedErrorCount: 0,
    88  		},
    89  		{
    90  			description: "Open Error",
    91  			testCase: func(m *Metrics) {
    92  				m.RecordConnectionAccept(false)
    93  			},
    94  			expectedOpenedCount:      0,
    95  			expectedOpenedErrorCount: 1,
    96  			expectedClosedCount:      0,
    97  			expectedClosedErrorCount: 0,
    98  		},
    99  		{
   100  			description: "Closed Success",
   101  			testCase: func(m *Metrics) {
   102  				m.RecordConnectionClose(true)
   103  			},
   104  			expectedOpenedCount:      0,
   105  			expectedOpenedErrorCount: 0,
   106  			expectedClosedCount:      1,
   107  			expectedClosedErrorCount: 0,
   108  		},
   109  		{
   110  			description: "Closed Error",
   111  			testCase: func(m *Metrics) {
   112  				m.RecordConnectionClose(false)
   113  			},
   114  			expectedOpenedCount:      0,
   115  			expectedOpenedErrorCount: 0,
   116  			expectedClosedCount:      0,
   117  			expectedClosedErrorCount: 1,
   118  		},
   119  	}
   120  
   121  	for _, test := range testCases {
   122  		m := createMetricsForTesting()
   123  
   124  		test.testCase(m)
   125  
   126  		assertCounterValue(t, test.description, "connectionsClosed", m.connectionsClosed,
   127  			test.expectedClosedCount)
   128  		assertCounterValue(t, test.description, "connectionsOpened", m.connectionsOpened,
   129  			test.expectedOpenedCount)
   130  		assertCounterVecValue(t, test.description, "connectionsError[type=accept]", m.connectionsError,
   131  			test.expectedOpenedErrorCount, prometheus.Labels{
   132  				connectionErrorLabel: connectionAcceptError,
   133  			})
   134  		assertCounterVecValue(t, test.description, "connectionsError[type=close]", m.connectionsError,
   135  			test.expectedClosedErrorCount, prometheus.Labels{
   136  				connectionErrorLabel: connectionCloseError,
   137  			})
   138  	}
   139  }
   140  
   141  func TestRequestMetric(t *testing.T) {
   142  	m := createMetricsForTesting()
   143  	requestType := metrics.ReqTypeORTB2Web
   144  	requestStatus := metrics.RequestStatusBlacklisted
   145  
   146  	m.RecordRequest(metrics.Labels{
   147  		RType:         requestType,
   148  		RequestStatus: requestStatus,
   149  	})
   150  
   151  	expectedCount := float64(1)
   152  	assertCounterVecValue(t, "", "requests", m.requests,
   153  		expectedCount,
   154  		prometheus.Labels{
   155  			requestTypeLabel:   string(requestType),
   156  			requestStatusLabel: string(requestStatus),
   157  		})
   158  }
   159  
   160  func TestDebugRequestMetric(t *testing.T) {
   161  	testCases := []struct {
   162  		description                      string
   163  		givenDebugEnabledFlag            bool
   164  		givenAccountDebugMetricsDisabled bool
   165  		expectedAccountDebugCount        float64
   166  		expectedDebugCount               float64
   167  	}{
   168  		{
   169  			description:                      "Debug is enabled and account debug is enabled, both metrics should be updated",
   170  			givenDebugEnabledFlag:            true,
   171  			givenAccountDebugMetricsDisabled: false,
   172  			expectedDebugCount:               1,
   173  			expectedAccountDebugCount:        1,
   174  		},
   175  		{
   176  			description:                      "Debug and account debug are disabled, niether metrics should be updated",
   177  			givenDebugEnabledFlag:            false,
   178  			givenAccountDebugMetricsDisabled: true,
   179  			expectedDebugCount:               0,
   180  			expectedAccountDebugCount:        0,
   181  		},
   182  		{
   183  			description:                      "Debug is enabled but account debug is disabled, only non-account debug count should increment",
   184  			givenDebugEnabledFlag:            true,
   185  			givenAccountDebugMetricsDisabled: true,
   186  			expectedDebugCount:               1,
   187  			expectedAccountDebugCount:        0,
   188  		},
   189  		{
   190  			description:                      "Debug is disabled and account debug is enabled, niether metrics should increment",
   191  			givenDebugEnabledFlag:            false,
   192  			givenAccountDebugMetricsDisabled: false,
   193  			expectedDebugCount:               0,
   194  			expectedAccountDebugCount:        0,
   195  		},
   196  	}
   197  
   198  	for _, test := range testCases {
   199  		m := createMetricsForTesting()
   200  		m.metricsDisabled.AccountDebug = test.givenAccountDebugMetricsDisabled
   201  		m.RecordDebugRequest(test.givenDebugEnabledFlag, "acct-id")
   202  
   203  		assertCounterVecValue(t, "", "account debug requests", m.accountDebugRequests, test.expectedAccountDebugCount, prometheus.Labels{accountLabel: "acct-id"})
   204  		assertCounterValue(t, "", "debug requests", m.debugRequests, test.expectedDebugCount)
   205  	}
   206  }
   207  
   208  func TestBidValidationCreativeSizeMetric(t *testing.T) {
   209  	testCases := []struct {
   210  		description                        string
   211  		givenDebugEnabledFlag              bool
   212  		givenAccountAdapterMetricsDisabled bool
   213  		expectedAdapterCount               float64
   214  		expectedAccountCount               float64
   215  	}{
   216  		{
   217  			description:                        "Account Metric isn't disabled, so both metrics should be incremented",
   218  			givenAccountAdapterMetricsDisabled: false,
   219  			expectedAdapterCount:               1,
   220  			expectedAccountCount:               1,
   221  		},
   222  		{
   223  			description:                        "Account Metric is disabled, so only adapter metric should be incremented",
   224  			givenAccountAdapterMetricsDisabled: true,
   225  			expectedAdapterCount:               1,
   226  			expectedAccountCount:               0,
   227  		},
   228  	}
   229  	adapterName := openrtb_ext.BidderName("AnyName")
   230  	lowerCasedAdapterName := "anyname"
   231  	for _, test := range testCases {
   232  		m := createMetricsForTesting()
   233  		m.metricsDisabled.AccountAdapterDetails = test.givenAccountAdapterMetricsDisabled
   234  		m.RecordBidValidationCreativeSizeError(adapterName, "acct-id")
   235  		m.RecordBidValidationCreativeSizeWarn(adapterName, "acct-id")
   236  
   237  		assertCounterVecValue(t, "", "account bid validation", m.accountBidResponseValidationSizeError, test.expectedAccountCount, prometheus.Labels{accountLabel: "acct-id", successLabel: successLabel})
   238  		assertCounterVecValue(t, "", "adapter bid validation", m.adapterBidResponseValidationSizeError, test.expectedAdapterCount, prometheus.Labels{adapterLabel: lowerCasedAdapterName, successLabel: successLabel})
   239  
   240  		assertCounterVecValue(t, "", "account bid validation", m.accountBidResponseValidationSizeWarn, test.expectedAccountCount, prometheus.Labels{accountLabel: "acct-id", successLabel: successLabel})
   241  		assertCounterVecValue(t, "", "adapter bid validation", m.adapterBidResponseValidationSizeWarn, test.expectedAdapterCount, prometheus.Labels{adapterLabel: lowerCasedAdapterName, successLabel: successLabel})
   242  	}
   243  }
   244  
   245  func TestBidValidationSecureMarkupMetric(t *testing.T) {
   246  	testCases := []struct {
   247  		description                        string
   248  		givenDebugEnabledFlag              bool
   249  		givenAccountAdapterMetricsDisabled bool
   250  		expectedAdapterCount               float64
   251  		expectedAccountCount               float64
   252  	}{
   253  		{
   254  			description:                        "Account Metric isn't disabled, so both metrics should be incremented",
   255  			givenAccountAdapterMetricsDisabled: false,
   256  			expectedAdapterCount:               1,
   257  			expectedAccountCount:               1,
   258  		},
   259  		{
   260  			description:                        "Account Metric is disabled, so only adapter metric should be incremented",
   261  			givenAccountAdapterMetricsDisabled: true,
   262  			expectedAdapterCount:               1,
   263  			expectedAccountCount:               0,
   264  		},
   265  	}
   266  
   267  	adapterName := openrtb_ext.BidderName("AnyName")
   268  	lowerCasedAdapterName := "anyname"
   269  	for _, test := range testCases {
   270  		m := createMetricsForTesting()
   271  		m.metricsDisabled.AccountAdapterDetails = test.givenAccountAdapterMetricsDisabled
   272  		m.RecordBidValidationSecureMarkupError(adapterName, "acct-id")
   273  		m.RecordBidValidationSecureMarkupWarn(adapterName, "acct-id")
   274  
   275  		assertCounterVecValue(t, "", "Account Secure Markup Error", m.accountBidResponseSecureMarkupError, test.expectedAccountCount, prometheus.Labels{accountLabel: "acct-id", successLabel: successLabel})
   276  		assertCounterVecValue(t, "", "Adapter Secure Markup Error", m.adapterBidResponseSecureMarkupError, test.expectedAdapterCount, prometheus.Labels{adapterLabel: lowerCasedAdapterName, successLabel: successLabel})
   277  
   278  		assertCounterVecValue(t, "", "Account Secure Markup Warn", m.accountBidResponseSecureMarkupWarn, test.expectedAccountCount, prometheus.Labels{accountLabel: "acct-id", successLabel: successLabel})
   279  		assertCounterVecValue(t, "", "Adapter Secure Markup Warn", m.adapterBidResponseSecureMarkupWarn, test.expectedAdapterCount, prometheus.Labels{adapterLabel: lowerCasedAdapterName, successLabel: successLabel})
   280  	}
   281  }
   282  
   283  func TestRequestMetricWithoutCookie(t *testing.T) {
   284  	requestType := metrics.ReqTypeORTB2Web
   285  	performTest := func(m *Metrics, cookieFlag metrics.CookieFlag) {
   286  		m.RecordRequest(metrics.Labels{
   287  			RType:         requestType,
   288  			RequestStatus: metrics.RequestStatusBlacklisted,
   289  			CookieFlag:    cookieFlag,
   290  		})
   291  	}
   292  
   293  	testCases := []struct {
   294  		description   string
   295  		testCase      func(m *Metrics)
   296  		cookieFlag    metrics.CookieFlag
   297  		expectedCount float64
   298  	}{
   299  		{
   300  			description: "Yes",
   301  			testCase: func(m *Metrics) {
   302  				performTest(m, metrics.CookieFlagYes)
   303  			},
   304  			expectedCount: 0,
   305  		},
   306  		{
   307  			description: "No",
   308  			testCase: func(m *Metrics) {
   309  				performTest(m, metrics.CookieFlagNo)
   310  			},
   311  			expectedCount: 1,
   312  		},
   313  		{
   314  			description: "Unknown",
   315  			testCase: func(m *Metrics) {
   316  				performTest(m, metrics.CookieFlagUnknown)
   317  			},
   318  			expectedCount: 0,
   319  		},
   320  	}
   321  
   322  	for _, test := range testCases {
   323  		m := createMetricsForTesting()
   324  
   325  		test.testCase(m)
   326  
   327  		assertCounterVecValue(t, test.description, "requestsWithoutCookie", m.requestsWithoutCookie,
   328  			test.expectedCount,
   329  			prometheus.Labels{
   330  				requestTypeLabel: string(requestType),
   331  			})
   332  	}
   333  }
   334  
   335  func TestAccountMetric(t *testing.T) {
   336  	knownPubID := "knownPublisher"
   337  	performTest := func(m *Metrics, pubID string) {
   338  		m.RecordRequest(metrics.Labels{
   339  			RType:         metrics.ReqTypeORTB2Web,
   340  			RequestStatus: metrics.RequestStatusBlacklisted,
   341  			PubID:         pubID,
   342  		})
   343  	}
   344  
   345  	testCases := []struct {
   346  		description   string
   347  		testCase      func(m *Metrics)
   348  		expectedCount float64
   349  	}{
   350  		{
   351  			description: "Known",
   352  			testCase: func(m *Metrics) {
   353  				performTest(m, knownPubID)
   354  			},
   355  			expectedCount: 1,
   356  		},
   357  		{
   358  			description: "Unknown",
   359  			testCase: func(m *Metrics) {
   360  				performTest(m, metrics.PublisherUnknown)
   361  			},
   362  			expectedCount: 0,
   363  		},
   364  	}
   365  
   366  	for _, test := range testCases {
   367  		m := createMetricsForTesting()
   368  
   369  		test.testCase(m)
   370  
   371  		assertCounterVecValue(t, test.description, "accountRequests", m.accountRequests,
   372  			test.expectedCount,
   373  			prometheus.Labels{
   374  				accountLabel: knownPubID,
   375  			})
   376  	}
   377  }
   378  
   379  func TestImpressionsMetric(t *testing.T) {
   380  	performTest := func(m *Metrics, isBanner, isVideo, isAudio, isNative bool) {
   381  		m.RecordImps(metrics.ImpLabels{
   382  			BannerImps: isBanner,
   383  			VideoImps:  isVideo,
   384  			AudioImps:  isAudio,
   385  			NativeImps: isNative,
   386  		})
   387  	}
   388  
   389  	testCases := []struct {
   390  		description         string
   391  		testCase            func(m *Metrics)
   392  		expectedBannerCount float64
   393  		expectedVideoCount  float64
   394  		expectedAudioCount  float64
   395  		expectedNativeCount float64
   396  	}{
   397  		{
   398  			description: "Banner Only",
   399  			testCase: func(m *Metrics) {
   400  				performTest(m, true, false, false, false)
   401  			},
   402  			expectedBannerCount: 1,
   403  			expectedVideoCount:  0,
   404  			expectedAudioCount:  0,
   405  			expectedNativeCount: 0,
   406  		},
   407  		{
   408  			description: "Video Only",
   409  			testCase: func(m *Metrics) {
   410  				performTest(m, false, true, false, false)
   411  			},
   412  			expectedBannerCount: 0,
   413  			expectedVideoCount:  1,
   414  			expectedAudioCount:  0,
   415  			expectedNativeCount: 0,
   416  		},
   417  		{
   418  			description: "Audio Only",
   419  			testCase: func(m *Metrics) {
   420  				performTest(m, false, false, true, false)
   421  			},
   422  			expectedBannerCount: 0,
   423  			expectedVideoCount:  0,
   424  			expectedAudioCount:  1,
   425  			expectedNativeCount: 0,
   426  		},
   427  		{
   428  			description: "Native Only",
   429  			testCase: func(m *Metrics) {
   430  				performTest(m, false, false, false, true)
   431  			},
   432  			expectedBannerCount: 0,
   433  			expectedVideoCount:  0,
   434  			expectedAudioCount:  0,
   435  			expectedNativeCount: 1,
   436  		},
   437  		{
   438  			description: "Multiple Types",
   439  			testCase: func(m *Metrics) {
   440  				performTest(m, true, false, false, true)
   441  			},
   442  			expectedBannerCount: 1,
   443  			expectedVideoCount:  0,
   444  			expectedAudioCount:  0,
   445  			expectedNativeCount: 1,
   446  		},
   447  	}
   448  
   449  	for _, test := range testCases {
   450  		m := createMetricsForTesting()
   451  
   452  		test.testCase(m)
   453  
   454  		var bannerCount float64
   455  		var videoCount float64
   456  		var audioCount float64
   457  		var nativeCount float64
   458  		processMetrics(m.impressions, func(m dto.Metric) {
   459  			value := m.GetCounter().GetValue()
   460  			for _, label := range m.GetLabel() {
   461  				if label.GetValue() == "true" {
   462  					switch label.GetName() {
   463  					case isBannerLabel:
   464  						bannerCount += value
   465  					case isVideoLabel:
   466  						videoCount += value
   467  					case isAudioLabel:
   468  						audioCount += value
   469  					case isNativeLabel:
   470  						nativeCount += value
   471  					}
   472  				}
   473  			}
   474  		})
   475  		assert.Equal(t, test.expectedBannerCount, bannerCount, test.description+":banner")
   476  		assert.Equal(t, test.expectedVideoCount, videoCount, test.description+":video")
   477  		assert.Equal(t, test.expectedAudioCount, audioCount, test.description+":audio")
   478  		assert.Equal(t, test.expectedNativeCount, nativeCount, test.description+":native")
   479  	}
   480  }
   481  
   482  func TestRequestTimeMetric(t *testing.T) {
   483  	requestType := metrics.ReqTypeORTB2Web
   484  	performTest := func(m *Metrics, requestStatus metrics.RequestStatus, timeInMs float64) {
   485  		m.RecordRequestTime(metrics.Labels{
   486  			RType:         requestType,
   487  			RequestStatus: requestStatus,
   488  		}, time.Duration(timeInMs)*time.Millisecond)
   489  	}
   490  
   491  	testCases := []struct {
   492  		description   string
   493  		testCase      func(m *Metrics)
   494  		expectedCount uint64
   495  		expectedSum   float64
   496  	}{
   497  		{
   498  			description: "Success",
   499  			testCase: func(m *Metrics) {
   500  				performTest(m, metrics.RequestStatusOK, 500)
   501  			},
   502  			expectedCount: 1,
   503  			expectedSum:   0.5,
   504  		},
   505  		{
   506  			description: "Error",
   507  			testCase: func(m *Metrics) {
   508  				performTest(m, metrics.RequestStatusErr, 500)
   509  			},
   510  			expectedCount: 0,
   511  			expectedSum:   0,
   512  		},
   513  	}
   514  
   515  	for _, test := range testCases {
   516  		m := createMetricsForTesting()
   517  
   518  		test.testCase(m)
   519  
   520  		result := getHistogramFromHistogramVec(m.requestsTimer, requestTypeLabel, string(requestType))
   521  		assertHistogram(t, test.description, result, test.expectedCount, test.expectedSum)
   522  	}
   523  }
   524  
   525  func TestRecordOverheadTimeMetric(t *testing.T) {
   526  	testCases := []struct {
   527  		description   string
   528  		overheadType  metrics.OverheadType
   529  		timeInMs      float64
   530  		expectedCount uint64
   531  		expectedSum   float64
   532  	}{
   533  		{
   534  			description:   "record-pre-bidder-overhead-time-1",
   535  			overheadType:  metrics.PreBidder,
   536  			timeInMs:      500,
   537  			expectedCount: 1,
   538  			expectedSum:   0.5,
   539  		},
   540  		{
   541  			description:   "record-pre-bidder-overhead-time-2",
   542  			overheadType:  metrics.PreBidder,
   543  			timeInMs:      400,
   544  			expectedCount: 2,
   545  			expectedSum:   0.9,
   546  		},
   547  		{
   548  			description:   "record-auction-response-overhead-time",
   549  			overheadType:  metrics.MakeAuctionResponse,
   550  			timeInMs:      500,
   551  			expectedCount: 1,
   552  			expectedSum:   0.5,
   553  		},
   554  		{
   555  			description:   "record-make-bidder-requests-overhead-time",
   556  			overheadType:  metrics.MakeBidderRequests,
   557  			timeInMs:      500,
   558  			expectedCount: 1,
   559  			expectedSum:   0.5,
   560  		},
   561  	}
   562  
   563  	metric := createMetricsForTesting()
   564  	for _, test := range testCases {
   565  		metric.RecordOverheadTime(test.overheadType, time.Duration(test.timeInMs)*time.Millisecond)
   566  		resultingHistogram := getHistogramFromHistogramVec(metric.overheadTimer, overheadTypeLabel, test.overheadType.String())
   567  		assertHistogram(t, test.description, resultingHistogram, test.expectedCount, test.expectedSum)
   568  	}
   569  }
   570  
   571  func TestRecordStoredDataFetchTime(t *testing.T) {
   572  	tests := []struct {
   573  		description string
   574  		dataType    metrics.StoredDataType
   575  		fetchType   metrics.StoredDataFetchType
   576  	}{
   577  		{
   578  			description: "Update stored account histogram with all label",
   579  			dataType:    metrics.AccountDataType,
   580  			fetchType:   metrics.FetchAll,
   581  		},
   582  		{
   583  			description: "Update stored AMP histogram with all label",
   584  			dataType:    metrics.AMPDataType,
   585  			fetchType:   metrics.FetchAll,
   586  		},
   587  		{
   588  			description: "Update stored category histogram with all label",
   589  			dataType:    metrics.CategoryDataType,
   590  			fetchType:   metrics.FetchAll,
   591  		},
   592  		{
   593  			description: "Update stored request histogram with all label",
   594  			dataType:    metrics.RequestDataType,
   595  			fetchType:   metrics.FetchAll,
   596  		},
   597  		{
   598  			description: "Update stored video histogram with all label",
   599  			dataType:    metrics.VideoDataType,
   600  			fetchType:   metrics.FetchAll,
   601  		},
   602  		{
   603  			description: "Update stored account histogram with delta label",
   604  			dataType:    metrics.AccountDataType,
   605  			fetchType:   metrics.FetchDelta,
   606  		},
   607  		{
   608  			description: "Update stored AMP histogram with delta label",
   609  			dataType:    metrics.AMPDataType,
   610  			fetchType:   metrics.FetchDelta,
   611  		},
   612  		{
   613  			description: "Update stored category histogram with delta label",
   614  			dataType:    metrics.CategoryDataType,
   615  			fetchType:   metrics.FetchDelta,
   616  		},
   617  		{
   618  			description: "Update stored request histogram with delta label",
   619  			dataType:    metrics.RequestDataType,
   620  			fetchType:   metrics.FetchDelta,
   621  		},
   622  		{
   623  			description: "Update stored video histogram with delta label",
   624  			dataType:    metrics.VideoDataType,
   625  			fetchType:   metrics.FetchDelta,
   626  		},
   627  		{
   628  			description: "Update stored responses histogram with delta label",
   629  			dataType:    metrics.ResponseDataType,
   630  			fetchType:   metrics.FetchDelta,
   631  		},
   632  	}
   633  
   634  	for _, tt := range tests {
   635  		m := createMetricsForTesting()
   636  
   637  		fetchTime := time.Duration(0.5 * float64(time.Second))
   638  		m.RecordStoredDataFetchTime(metrics.StoredDataLabels{
   639  			DataType:      tt.dataType,
   640  			DataFetchType: tt.fetchType,
   641  		}, fetchTime)
   642  
   643  		var metricsTimer *prometheus.HistogramVec
   644  		switch tt.dataType {
   645  		case metrics.AccountDataType:
   646  			metricsTimer = m.storedAccountFetchTimer
   647  		case metrics.AMPDataType:
   648  			metricsTimer = m.storedAMPFetchTimer
   649  		case metrics.CategoryDataType:
   650  			metricsTimer = m.storedCategoryFetchTimer
   651  		case metrics.RequestDataType:
   652  			metricsTimer = m.storedRequestFetchTimer
   653  		case metrics.VideoDataType:
   654  			metricsTimer = m.storedVideoFetchTimer
   655  		case metrics.ResponseDataType:
   656  			metricsTimer = m.storedResponsesFetchTimer
   657  		}
   658  
   659  		result := getHistogramFromHistogramVec(
   660  			metricsTimer,
   661  			storedDataFetchTypeLabel,
   662  			string(tt.fetchType))
   663  		assertHistogram(t, tt.description, result, 1, 0.5)
   664  	}
   665  }
   666  
   667  func TestRecordStoredDataError(t *testing.T) {
   668  	tests := []struct {
   669  		description string
   670  		dataType    metrics.StoredDataType
   671  		errorType   metrics.StoredDataError
   672  		metricName  string
   673  	}{
   674  		{
   675  			description: "Update stored_account_errors counter with network label",
   676  			dataType:    metrics.AccountDataType,
   677  			errorType:   metrics.StoredDataErrorNetwork,
   678  			metricName:  "stored_account_errors",
   679  		},
   680  		{
   681  			description: "Update stored_amp_errors counter with network label",
   682  			dataType:    metrics.AMPDataType,
   683  			errorType:   metrics.StoredDataErrorNetwork,
   684  			metricName:  "stored_amp_errors",
   685  		},
   686  		{
   687  			description: "Update stored_category_errors counter with network label",
   688  			dataType:    metrics.CategoryDataType,
   689  			errorType:   metrics.StoredDataErrorNetwork,
   690  			metricName:  "stored_category_errors",
   691  		},
   692  		{
   693  			description: "Update stored_request_errors counter with network label",
   694  			dataType:    metrics.RequestDataType,
   695  			errorType:   metrics.StoredDataErrorNetwork,
   696  			metricName:  "stored_request_errors",
   697  		},
   698  		{
   699  			description: "Update stored_video_errors counter with network label",
   700  			dataType:    metrics.VideoDataType,
   701  			errorType:   metrics.StoredDataErrorNetwork,
   702  			metricName:  "stored_video_errors",
   703  		},
   704  		{
   705  			description: "Update stored_account_errors counter with undefined label",
   706  			dataType:    metrics.AccountDataType,
   707  			errorType:   metrics.StoredDataErrorUndefined,
   708  			metricName:  "stored_account_errors",
   709  		},
   710  		{
   711  			description: "Update stored_amp_errors counter with undefined label",
   712  			dataType:    metrics.AMPDataType,
   713  			errorType:   metrics.StoredDataErrorUndefined,
   714  			metricName:  "stored_amp_errors",
   715  		},
   716  		{
   717  			description: "Update stored_category_errors counter with undefined label",
   718  			dataType:    metrics.CategoryDataType,
   719  			errorType:   metrics.StoredDataErrorUndefined,
   720  			metricName:  "stored_category_errors",
   721  		},
   722  		{
   723  			description: "Update stored_request_errors counter with undefined label",
   724  			dataType:    metrics.RequestDataType,
   725  			errorType:   metrics.StoredDataErrorUndefined,
   726  			metricName:  "stored_request_errors",
   727  		},
   728  		{
   729  			description: "Update stored_video_errors counter with undefined label",
   730  			dataType:    metrics.VideoDataType,
   731  			errorType:   metrics.StoredDataErrorUndefined,
   732  			metricName:  "stored_video_errors",
   733  		},
   734  		{
   735  			description: "Update stored_response_errors counter with network label",
   736  			dataType:    metrics.ResponseDataType,
   737  			errorType:   metrics.StoredDataErrorNetwork,
   738  			metricName:  "stored_response_errors",
   739  		},
   740  	}
   741  
   742  	for _, tt := range tests {
   743  		m := createMetricsForTesting()
   744  		m.RecordStoredDataError(metrics.StoredDataLabels{
   745  			DataType: tt.dataType,
   746  			Error:    tt.errorType,
   747  		})
   748  
   749  		var metricsCounter *prometheus.CounterVec
   750  		switch tt.dataType {
   751  		case metrics.AccountDataType:
   752  			metricsCounter = m.storedAccountErrors
   753  		case metrics.AMPDataType:
   754  			metricsCounter = m.storedAMPErrors
   755  		case metrics.CategoryDataType:
   756  			metricsCounter = m.storedCategoryErrors
   757  		case metrics.RequestDataType:
   758  			metricsCounter = m.storedRequestErrors
   759  		case metrics.VideoDataType:
   760  			metricsCounter = m.storedVideoErrors
   761  		case metrics.ResponseDataType:
   762  			metricsCounter = m.storedResponsesErrors
   763  		}
   764  
   765  		assertCounterVecValue(t, tt.description, tt.metricName, metricsCounter,
   766  			1,
   767  			prometheus.Labels{
   768  				storedDataErrorLabel: string(tt.errorType),
   769  			})
   770  	}
   771  }
   772  
   773  func TestAdapterBidReceivedMetric(t *testing.T) {
   774  	adapterName := openrtb_ext.BidderName("anyName")
   775  	lowerCasedAdapterName := "anyname"
   776  	performTest := func(m *Metrics, hasAdm bool) {
   777  		labels := metrics.AdapterLabels{
   778  			Adapter: adapterName,
   779  		}
   780  		bidType := openrtb_ext.BidTypeBanner
   781  		m.RecordAdapterBidReceived(labels, bidType, hasAdm)
   782  	}
   783  
   784  	testCases := []struct {
   785  		description       string
   786  		testCase          func(m *Metrics)
   787  		expectedAdmCount  float64
   788  		expectedNurlCount float64
   789  	}{
   790  		{
   791  			description: "AdM",
   792  			testCase: func(m *Metrics) {
   793  				performTest(m, true)
   794  			},
   795  			expectedAdmCount:  1,
   796  			expectedNurlCount: 0,
   797  		},
   798  		{
   799  			description: "Nurl",
   800  			testCase: func(m *Metrics) {
   801  				performTest(m, false)
   802  			},
   803  			expectedAdmCount:  0,
   804  			expectedNurlCount: 1,
   805  		},
   806  	}
   807  
   808  	for _, test := range testCases {
   809  		m := createMetricsForTesting()
   810  
   811  		test.testCase(m)
   812  
   813  		assertCounterVecValue(t, test.description, "adapterBids[adm]", m.adapterBids,
   814  			test.expectedAdmCount,
   815  			prometheus.Labels{
   816  				adapterLabel:        lowerCasedAdapterName,
   817  				markupDeliveryLabel: markupDeliveryAdm,
   818  			})
   819  		assertCounterVecValue(t, test.description, "adapterBids[nurl]", m.adapterBids,
   820  			test.expectedNurlCount,
   821  			prometheus.Labels{
   822  				adapterLabel:        lowerCasedAdapterName,
   823  				markupDeliveryLabel: markupDeliveryNurl,
   824  			})
   825  	}
   826  }
   827  
   828  func TestRecordAdapterPriceMetric(t *testing.T) {
   829  	m := createMetricsForTesting()
   830  	adapterName := "anyName"
   831  	lowerCasedAdapterName := "anyname"
   832  	cpm := float64(42)
   833  
   834  	m.RecordAdapterPrice(metrics.AdapterLabels{
   835  		Adapter: openrtb_ext.BidderName(adapterName),
   836  	}, cpm)
   837  
   838  	expectedCount := uint64(1)
   839  	expectedSum := cpm
   840  	result := getHistogramFromHistogramVec(m.adapterPrices, adapterLabel, lowerCasedAdapterName)
   841  	assertHistogram(t, "adapterPrices", result, expectedCount, expectedSum)
   842  }
   843  
   844  func TestAdapterRequestMetrics(t *testing.T) {
   845  	adapterName := "anyName"
   846  	lowerCasedAdapterName := "anyname"
   847  	performTest := func(m *Metrics, cookieFlag metrics.CookieFlag, adapterBids metrics.AdapterBid) {
   848  		labels := metrics.AdapterLabels{
   849  			Adapter:     openrtb_ext.BidderName(adapterName),
   850  			CookieFlag:  cookieFlag,
   851  			AdapterBids: adapterBids,
   852  		}
   853  		m.RecordAdapterRequest(labels)
   854  	}
   855  
   856  	testCases := []struct {
   857  		description                string
   858  		testCase                   func(m *Metrics)
   859  		expectedCount              float64
   860  		expectedCookieNoCount      float64
   861  		expectedCookieYesCount     float64
   862  		expectedCookieUnknownCount float64
   863  		expectedHasBidsCount       float64
   864  	}{
   865  		{
   866  			description: "No Cookie & No Bids",
   867  			testCase: func(m *Metrics) {
   868  				performTest(m, metrics.CookieFlagNo, metrics.AdapterBidNone)
   869  			},
   870  			expectedCount:              1,
   871  			expectedCookieNoCount:      1,
   872  			expectedCookieYesCount:     0,
   873  			expectedCookieUnknownCount: 0,
   874  			expectedHasBidsCount:       0,
   875  		},
   876  		{
   877  			description: "Unknown Cookie & No Bids",
   878  			testCase: func(m *Metrics) {
   879  				performTest(m, metrics.CookieFlagUnknown, metrics.AdapterBidNone)
   880  			},
   881  			expectedCount:              1,
   882  			expectedCookieNoCount:      0,
   883  			expectedCookieYesCount:     0,
   884  			expectedCookieUnknownCount: 1,
   885  			expectedHasBidsCount:       0,
   886  		},
   887  		{
   888  			description: "Has Cookie & No Bids",
   889  			testCase: func(m *Metrics) {
   890  				performTest(m, metrics.CookieFlagYes, metrics.AdapterBidNone)
   891  			},
   892  			expectedCount:              1,
   893  			expectedCookieNoCount:      0,
   894  			expectedCookieYesCount:     1,
   895  			expectedCookieUnknownCount: 0,
   896  			expectedHasBidsCount:       0,
   897  		},
   898  		{
   899  			description: "No Cookie & Bids Present",
   900  			testCase: func(m *Metrics) {
   901  				performTest(m, metrics.CookieFlagNo, metrics.AdapterBidPresent)
   902  			},
   903  			expectedCount:              1,
   904  			expectedCookieNoCount:      1,
   905  			expectedCookieYesCount:     0,
   906  			expectedCookieUnknownCount: 0,
   907  			expectedHasBidsCount:       1,
   908  		},
   909  		{
   910  			description: "Unknown Cookie & Bids Present",
   911  			testCase: func(m *Metrics) {
   912  				performTest(m, metrics.CookieFlagUnknown, metrics.AdapterBidPresent)
   913  			},
   914  			expectedCount:              1,
   915  			expectedCookieNoCount:      0,
   916  			expectedCookieYesCount:     0,
   917  			expectedCookieUnknownCount: 1,
   918  			expectedHasBidsCount:       1,
   919  		},
   920  		{
   921  			description: "Has Cookie & Bids Present",
   922  			testCase: func(m *Metrics) {
   923  				performTest(m, metrics.CookieFlagYes, metrics.AdapterBidPresent)
   924  			},
   925  			expectedCount:              1,
   926  			expectedCookieNoCount:      0,
   927  			expectedCookieYesCount:     1,
   928  			expectedCookieUnknownCount: 0,
   929  			expectedHasBidsCount:       1,
   930  		},
   931  	}
   932  
   933  	for _, test := range testCases {
   934  		m := createMetricsForTesting()
   935  
   936  		test.testCase(m)
   937  
   938  		var totalCount float64
   939  		var totalCookieNoCount float64
   940  		var totalCookieYesCount float64
   941  		var totalCookieUnknownCount float64
   942  		var totalHasBidsCount float64
   943  		processMetrics(m.adapterRequests, func(m dto.Metric) {
   944  			isMetricForAdapter := false
   945  			for _, label := range m.GetLabel() {
   946  				if label.GetName() == adapterLabel && label.GetValue() == lowerCasedAdapterName {
   947  					isMetricForAdapter = true
   948  				}
   949  			}
   950  
   951  			if isMetricForAdapter {
   952  				value := m.GetCounter().GetValue()
   953  				totalCount += value
   954  				for _, label := range m.GetLabel() {
   955  
   956  					if label.GetName() == hasBidsLabel && label.GetValue() == "true" {
   957  						totalHasBidsCount += value
   958  					}
   959  
   960  					if label.GetName() == cookieLabel {
   961  						switch label.GetValue() {
   962  						case string(metrics.CookieFlagNo):
   963  							totalCookieNoCount += value
   964  						case string(metrics.CookieFlagYes):
   965  							totalCookieYesCount += value
   966  						case string(metrics.CookieFlagUnknown):
   967  							totalCookieUnknownCount += value
   968  						}
   969  					}
   970  				}
   971  			}
   972  		})
   973  		assert.Equal(t, test.expectedCount, totalCount, test.description+":total")
   974  		assert.Equal(t, test.expectedCookieNoCount, totalCookieNoCount, test.description+":cookie=no")
   975  		assert.Equal(t, test.expectedCookieYesCount, totalCookieYesCount, test.description+":cookie=yes")
   976  		assert.Equal(t, test.expectedCookieUnknownCount, totalCookieUnknownCount, test.description+":cookie=unknown")
   977  		assert.Equal(t, test.expectedHasBidsCount, totalHasBidsCount, test.description+":hasBids")
   978  	}
   979  }
   980  
   981  func TestAdapterRequestErrorMetrics(t *testing.T) {
   982  	adapterName := "anyName"
   983  	lowerCasedAdapterName := "anyname"
   984  	performTest := func(m *Metrics, adapterErrors map[metrics.AdapterError]struct{}) {
   985  		labels := metrics.AdapterLabels{
   986  			Adapter:       openrtb_ext.BidderName(adapterName),
   987  			AdapterErrors: adapterErrors,
   988  			CookieFlag:    metrics.CookieFlagUnknown,
   989  			AdapterBids:   metrics.AdapterBidPresent,
   990  		}
   991  		m.RecordAdapterRequest(labels)
   992  	}
   993  
   994  	testCases := []struct {
   995  		description                 string
   996  		testCase                    func(m *Metrics)
   997  		expectedErrorsCount         float64
   998  		expectedBadInputErrorsCount float64
   999  	}{
  1000  		{
  1001  			description: "No Errors",
  1002  			testCase: func(m *Metrics) {
  1003  				performTest(m, nil)
  1004  			},
  1005  			expectedErrorsCount:         0,
  1006  			expectedBadInputErrorsCount: 0,
  1007  		},
  1008  		{
  1009  			description: "Bad Input Error",
  1010  			testCase: func(m *Metrics) {
  1011  				performTest(m, map[metrics.AdapterError]struct{}{
  1012  					metrics.AdapterErrorBadInput: {},
  1013  				})
  1014  			},
  1015  			expectedErrorsCount:         1,
  1016  			expectedBadInputErrorsCount: 1,
  1017  		},
  1018  		{
  1019  			description: "Other Error",
  1020  			testCase: func(m *Metrics) {
  1021  				performTest(m, map[metrics.AdapterError]struct{}{
  1022  					metrics.AdapterErrorBadServerResponse: {},
  1023  				})
  1024  			},
  1025  			expectedErrorsCount:         1,
  1026  			expectedBadInputErrorsCount: 0,
  1027  		},
  1028  	}
  1029  
  1030  	for _, test := range testCases {
  1031  		m := createMetricsForTesting()
  1032  
  1033  		test.testCase(m)
  1034  
  1035  		var errorsCount float64
  1036  		var badInputErrorsCount float64
  1037  		processMetrics(m.adapterErrors, func(m dto.Metric) {
  1038  			isMetricForAdapter := false
  1039  			for _, label := range m.GetLabel() {
  1040  				if label.GetName() == adapterLabel && label.GetValue() == lowerCasedAdapterName {
  1041  					isMetricForAdapter = true
  1042  				}
  1043  			}
  1044  
  1045  			if isMetricForAdapter {
  1046  				value := m.GetCounter().GetValue()
  1047  				errorsCount += value
  1048  				for _, label := range m.GetLabel() {
  1049  					if label.GetName() == adapterErrorLabel && label.GetValue() == string(metrics.AdapterErrorBadInput) {
  1050  						badInputErrorsCount += value
  1051  					}
  1052  				}
  1053  			}
  1054  		})
  1055  		assert.Equal(t, test.expectedErrorsCount, errorsCount, test.description+":errors")
  1056  		assert.Equal(t, test.expectedBadInputErrorsCount, badInputErrorsCount, test.description+":badInputErrors")
  1057  	}
  1058  }
  1059  
  1060  func TestAdapterTimeMetric(t *testing.T) {
  1061  	adapterName := "anyName"
  1062  	lowerCasedAdapterName := "anyname"
  1063  	performTest := func(m *Metrics, timeInMs float64, adapterErrors map[metrics.AdapterError]struct{}) {
  1064  		m.RecordAdapterTime(metrics.AdapterLabels{
  1065  			Adapter:       openrtb_ext.BidderName(adapterName),
  1066  			AdapterErrors: adapterErrors,
  1067  		}, time.Duration(timeInMs)*time.Millisecond)
  1068  	}
  1069  
  1070  	testCases := []struct {
  1071  		description   string
  1072  		testCase      func(m *Metrics)
  1073  		expectedCount uint64
  1074  		expectedSum   float64
  1075  	}{
  1076  		{
  1077  			description: "Success",
  1078  			testCase: func(m *Metrics) {
  1079  				performTest(m, 500, map[metrics.AdapterError]struct{}{})
  1080  			},
  1081  			expectedCount: 1,
  1082  			expectedSum:   0.5,
  1083  		},
  1084  		{
  1085  			description: "Error",
  1086  			testCase: func(m *Metrics) {
  1087  				performTest(m, 500, map[metrics.AdapterError]struct{}{
  1088  					metrics.AdapterErrorTimeout: {},
  1089  				})
  1090  			},
  1091  			expectedCount: 0,
  1092  			expectedSum:   0,
  1093  		},
  1094  	}
  1095  
  1096  	for _, test := range testCases {
  1097  		m := createMetricsForTesting()
  1098  
  1099  		test.testCase(m)
  1100  
  1101  		result := getHistogramFromHistogramVec(m.adapterRequestsTimer, adapterLabel, lowerCasedAdapterName)
  1102  		assertHistogram(t, test.description, result, test.expectedCount, test.expectedSum)
  1103  	}
  1104  }
  1105  
  1106  func TestAdapterPanicMetric(t *testing.T) {
  1107  	m := createMetricsForTesting()
  1108  	adapterName := openrtb_ext.BidderName("anyName")
  1109  	lowerCasedAdapterName := "anyname"
  1110  	m.RecordAdapterPanic(metrics.AdapterLabels{
  1111  		Adapter: adapterName,
  1112  	})
  1113  
  1114  	expectedCount := float64(1)
  1115  	assertCounterVecValue(t, "", "adapterPanics", m.adapterPanics,
  1116  		expectedCount,
  1117  		prometheus.Labels{
  1118  			adapterLabel: lowerCasedAdapterName,
  1119  		})
  1120  }
  1121  
  1122  func TestStoredReqCacheResultMetric(t *testing.T) {
  1123  	m := createMetricsForTesting()
  1124  
  1125  	hitCount := 42
  1126  	missCount := 108
  1127  	m.RecordStoredReqCacheResult(metrics.CacheHit, hitCount)
  1128  	m.RecordStoredReqCacheResult(metrics.CacheMiss, missCount)
  1129  
  1130  	assertCounterVecValue(t, "", "storedRequestCacheResult:hit", m.storedRequestCacheResult,
  1131  		float64(hitCount),
  1132  		prometheus.Labels{
  1133  			cacheResultLabel: string(metrics.CacheHit),
  1134  		})
  1135  	assertCounterVecValue(t, "", "storedRequestCacheResult:miss", m.storedRequestCacheResult,
  1136  		float64(missCount),
  1137  		prometheus.Labels{
  1138  			cacheResultLabel: string(metrics.CacheMiss),
  1139  		})
  1140  }
  1141  
  1142  func TestStoredImpCacheResultMetric(t *testing.T) {
  1143  	m := createMetricsForTesting()
  1144  
  1145  	hitCount := 41
  1146  	missCount := 107
  1147  	m.RecordStoredImpCacheResult(metrics.CacheHit, hitCount)
  1148  	m.RecordStoredImpCacheResult(metrics.CacheMiss, missCount)
  1149  
  1150  	assertCounterVecValue(t, "", "storedImpressionsCacheResult:hit", m.storedImpressionsCacheResult,
  1151  		float64(hitCount),
  1152  		prometheus.Labels{
  1153  			cacheResultLabel: string(metrics.CacheHit),
  1154  		})
  1155  	assertCounterVecValue(t, "", "storedImpressionsCacheResult:miss", m.storedImpressionsCacheResult,
  1156  		float64(missCount),
  1157  		prometheus.Labels{
  1158  			cacheResultLabel: string(metrics.CacheMiss),
  1159  		})
  1160  }
  1161  
  1162  func TestAccountCacheResultMetric(t *testing.T) {
  1163  	m := createMetricsForTesting()
  1164  
  1165  	hitCount := 37
  1166  	missCount := 92
  1167  	m.RecordAccountCacheResult(metrics.CacheHit, hitCount)
  1168  	m.RecordAccountCacheResult(metrics.CacheMiss, missCount)
  1169  
  1170  	assertCounterVecValue(t, "", "accountCacheResult:hit", m.accountCacheResult,
  1171  		float64(hitCount),
  1172  		prometheus.Labels{
  1173  			cacheResultLabel: string(metrics.CacheHit),
  1174  		})
  1175  	assertCounterVecValue(t, "", "accountCacheResult:miss", m.accountCacheResult,
  1176  		float64(missCount),
  1177  		prometheus.Labels{
  1178  			cacheResultLabel: string(metrics.CacheMiss),
  1179  		})
  1180  }
  1181  
  1182  func TestCookieSyncMetric(t *testing.T) {
  1183  	tests := []struct {
  1184  		status metrics.CookieSyncStatus
  1185  		label  string
  1186  	}{
  1187  		{
  1188  			status: metrics.CookieSyncOK,
  1189  			label:  "ok",
  1190  		},
  1191  		{
  1192  			status: metrics.CookieSyncBadRequest,
  1193  			label:  "bad_request",
  1194  		},
  1195  		{
  1196  			status: metrics.CookieSyncOptOut,
  1197  			label:  "opt_out",
  1198  		},
  1199  		{
  1200  			status: metrics.CookieSyncGDPRHostCookieBlocked,
  1201  			label:  "gdpr_blocked_host_cookie",
  1202  		},
  1203  	}
  1204  
  1205  	for _, test := range tests {
  1206  		m := createMetricsForTesting()
  1207  
  1208  		m.RecordCookieSync(test.status)
  1209  
  1210  		assertCounterVecValue(t, "", "cookie_sync_requests:"+test.label, m.cookieSync,
  1211  			float64(1),
  1212  			prometheus.Labels{
  1213  				statusLabel: string(test.status),
  1214  			})
  1215  	}
  1216  }
  1217  
  1218  func TestRecordSyncerRequestMetric(t *testing.T) {
  1219  	key := "anyKey"
  1220  
  1221  	tests := []struct {
  1222  		status metrics.SyncerCookieSyncStatus
  1223  		label  string
  1224  	}{
  1225  		{
  1226  			status: metrics.SyncerCookieSyncOK,
  1227  			label:  "ok",
  1228  		},
  1229  		{
  1230  			status: metrics.SyncerCookieSyncPrivacyBlocked,
  1231  			label:  "privacy_blocked",
  1232  		},
  1233  		{
  1234  			status: metrics.SyncerCookieSyncAlreadySynced,
  1235  			label:  "already_synced",
  1236  		},
  1237  		{
  1238  			status: metrics.SyncerCookieSyncTypeNotSupported,
  1239  			label:  "type_not_supported",
  1240  		},
  1241  	}
  1242  
  1243  	for _, test := range tests {
  1244  		m := createMetricsForTesting()
  1245  
  1246  		m.RecordSyncerRequest(key, test.status)
  1247  
  1248  		assertCounterVecValue(t, "", "syncer_requests:"+test.label, m.syncerRequests,
  1249  			float64(1),
  1250  			prometheus.Labels{
  1251  				syncerLabel: key,
  1252  				statusLabel: string(test.status),
  1253  			})
  1254  	}
  1255  }
  1256  
  1257  func TestSetUidMetric(t *testing.T) {
  1258  	tests := []struct {
  1259  		status metrics.SetUidStatus
  1260  		label  string
  1261  	}{
  1262  		{
  1263  			status: metrics.SetUidOK,
  1264  			label:  "ok",
  1265  		},
  1266  		{
  1267  			status: metrics.SetUidBadRequest,
  1268  			label:  "bad_request",
  1269  		},
  1270  		{
  1271  			status: metrics.SetUidOptOut,
  1272  			label:  "opt_out",
  1273  		},
  1274  		{
  1275  			status: metrics.SetUidGDPRHostCookieBlocked,
  1276  			label:  "gdpr_blocked_host_cookie",
  1277  		},
  1278  		{
  1279  			status: metrics.SetUidSyncerUnknown,
  1280  			label:  "syncer_unknown",
  1281  		},
  1282  	}
  1283  
  1284  	for _, test := range tests {
  1285  		m := createMetricsForTesting()
  1286  
  1287  		m.RecordSetUid(test.status)
  1288  
  1289  		assertCounterVecValue(t, "", "setuid_requests:"+test.label, m.setUid,
  1290  			float64(1),
  1291  			prometheus.Labels{
  1292  				statusLabel: string(test.status),
  1293  			})
  1294  	}
  1295  }
  1296  
  1297  func TestRecordSyncerSetMetric(t *testing.T) {
  1298  	key := "anyKey"
  1299  
  1300  	tests := []struct {
  1301  		status metrics.SyncerSetUidStatus
  1302  		label  string
  1303  	}{
  1304  		{
  1305  			status: metrics.SyncerSetUidOK,
  1306  			label:  "ok",
  1307  		},
  1308  		{
  1309  			status: metrics.SyncerSetUidCleared,
  1310  			label:  "cleared",
  1311  		},
  1312  	}
  1313  
  1314  	for _, test := range tests {
  1315  		m := createMetricsForTesting()
  1316  
  1317  		m.RecordSyncerSet(key, test.status)
  1318  
  1319  		assertCounterVecValue(t, "", "syncer_sets:"+test.label, m.syncerSets,
  1320  			float64(1),
  1321  			prometheus.Labels{
  1322  				syncerLabel: key,
  1323  				statusLabel: string(test.status),
  1324  			})
  1325  	}
  1326  }
  1327  
  1328  func TestPrebidCacheRequestTimeMetric(t *testing.T) {
  1329  	m := createMetricsForTesting()
  1330  
  1331  	m.RecordPrebidCacheRequestTime(true, time.Duration(100)*time.Millisecond)
  1332  	m.RecordPrebidCacheRequestTime(false, time.Duration(200)*time.Millisecond)
  1333  
  1334  	successExpectedCount := uint64(1)
  1335  	successExpectedSum := float64(0.1)
  1336  	successResult := getHistogramFromHistogramVec(m.prebidCacheWriteTimer, successLabel, "true")
  1337  	assertHistogram(t, "Success", successResult, successExpectedCount, successExpectedSum)
  1338  
  1339  	errorExpectedCount := uint64(1)
  1340  	errorExpectedSum := float64(0.2)
  1341  	errorResult := getHistogramFromHistogramVec(m.prebidCacheWriteTimer, successLabel, "false")
  1342  	assertHistogram(t, "Error", errorResult, errorExpectedCount, errorExpectedSum)
  1343  }
  1344  
  1345  func TestRecordRequestQueueTimeMetric(t *testing.T) {
  1346  	performTest := func(m *Metrics, requestStatus bool, requestType metrics.RequestType, timeInSec float64) {
  1347  		m.RecordRequestQueueTime(requestStatus, requestType, time.Duration(timeInSec*float64(time.Second)))
  1348  	}
  1349  
  1350  	testCases := []struct {
  1351  		description   string
  1352  		status        string
  1353  		testCase      func(m *Metrics)
  1354  		expectedCount uint64
  1355  		expectedSum   float64
  1356  	}{
  1357  		{
  1358  			description: "Success",
  1359  			status:      requestSuccessLabel,
  1360  			testCase: func(m *Metrics) {
  1361  				performTest(m, true, metrics.ReqTypeVideo, 2)
  1362  			},
  1363  			expectedCount: 1,
  1364  			expectedSum:   2,
  1365  		},
  1366  		{
  1367  			description: "TimeoutError",
  1368  			status:      requestRejectLabel,
  1369  			testCase: func(m *Metrics) {
  1370  				performTest(m, false, metrics.ReqTypeVideo, 50)
  1371  			},
  1372  			expectedCount: 1,
  1373  			expectedSum:   50,
  1374  		},
  1375  	}
  1376  
  1377  	m := createMetricsForTesting()
  1378  	for _, test := range testCases {
  1379  
  1380  		test.testCase(m)
  1381  
  1382  		result := getHistogramFromHistogramVecByTwoKeys(m.requestsQueueTimer, requestTypeLabel, "video", requestStatusLabel, test.status)
  1383  		assertHistogram(t, test.description, result, test.expectedCount, test.expectedSum)
  1384  	}
  1385  }
  1386  
  1387  func TestTimeoutNotifications(t *testing.T) {
  1388  	m := createMetricsForTesting()
  1389  
  1390  	m.RecordTimeoutNotice(true)
  1391  	m.RecordTimeoutNotice(true)
  1392  	m.RecordTimeoutNotice(false)
  1393  
  1394  	assertCounterVecValue(t, "", "timeout_notifications:ok", m.timeoutNotifications,
  1395  		float64(2),
  1396  		prometheus.Labels{
  1397  			successLabel: requestSuccessful,
  1398  		})
  1399  
  1400  	assertCounterVecValue(t, "", "timeout_notifications:fail", m.timeoutNotifications,
  1401  		float64(1),
  1402  		prometheus.Labels{
  1403  			successLabel: requestFailed,
  1404  		})
  1405  
  1406  }
  1407  
  1408  func TestRecordDNSTime(t *testing.T) {
  1409  	type testIn struct {
  1410  		dnsLookupDuration time.Duration
  1411  	}
  1412  	type testOut struct {
  1413  		expDuration float64
  1414  		expCount    uint64
  1415  	}
  1416  	testCases := []struct {
  1417  		description string
  1418  		in          testIn
  1419  		out         testOut
  1420  	}{
  1421  		{
  1422  			description: "Five second DNS lookup time",
  1423  			in: testIn{
  1424  				dnsLookupDuration: time.Second * 5,
  1425  			},
  1426  			out: testOut{
  1427  				expDuration: 5,
  1428  				expCount:    1,
  1429  			},
  1430  		},
  1431  		{
  1432  			description: "Zero DNS lookup time",
  1433  			in:          testIn{},
  1434  			out: testOut{
  1435  				expDuration: 0,
  1436  				expCount:    1,
  1437  			},
  1438  		},
  1439  	}
  1440  	for i, test := range testCases {
  1441  		pm := createMetricsForTesting()
  1442  		pm.RecordDNSTime(test.in.dnsLookupDuration)
  1443  
  1444  		m := dto.Metric{}
  1445  		pm.dnsLookupTimer.Write(&m)
  1446  		histogram := *m.GetHistogram()
  1447  
  1448  		assert.Equal(t, test.out.expCount, histogram.GetSampleCount(), "[%d] Incorrect number of histogram entries. Desc: %s\n", i, test.description)
  1449  		assert.Equal(t, test.out.expDuration, histogram.GetSampleSum(), "[%d] Incorrect number of histogram cumulative values. Desc: %s\n", i, test.description)
  1450  	}
  1451  }
  1452  
  1453  func TestRecordTLSHandshakeTime(t *testing.T) {
  1454  	testCases := []struct {
  1455  		description          string
  1456  		tLSHandshakeDuration time.Duration
  1457  		expectedDuration     float64
  1458  		expectedCount        uint64
  1459  	}{
  1460  		{
  1461  			description:          "Five second DNS lookup time",
  1462  			tLSHandshakeDuration: time.Second * 5,
  1463  			expectedDuration:     5,
  1464  			expectedCount:        1,
  1465  		},
  1466  		{
  1467  			description:          "Zero DNS lookup time",
  1468  			tLSHandshakeDuration: 0,
  1469  			expectedDuration:     0,
  1470  			expectedCount:        1,
  1471  		},
  1472  	}
  1473  	for i, test := range testCases {
  1474  		pm := createMetricsForTesting()
  1475  		pm.RecordTLSHandshakeTime(test.tLSHandshakeDuration)
  1476  
  1477  		m := dto.Metric{}
  1478  		pm.tlsHandhakeTimer.Write(&m)
  1479  		histogram := *m.GetHistogram()
  1480  
  1481  		assert.Equal(t, test.expectedCount, histogram.GetSampleCount(), "[%d] Incorrect number of histogram entries. Desc: %s\n", i, test.description)
  1482  		assert.Equal(t, test.expectedDuration, histogram.GetSampleSum(), "[%d] Incorrect number of histogram cumulative values. Desc: %s\n", i, test.description)
  1483  	}
  1484  }
  1485  
  1486  func TestRecordBidderServerResponseTime(t *testing.T) {
  1487  	testCases := []struct {
  1488  		description   string
  1489  		timeInMs      float64
  1490  		expectedCount uint64
  1491  		expectedSum   float64
  1492  	}{
  1493  		{
  1494  			description:   "record-bidder-server-response-time-1",
  1495  			timeInMs:      500,
  1496  			expectedCount: 1,
  1497  			expectedSum:   0.5,
  1498  		},
  1499  		{
  1500  			description:   "record-bidder-server-response-time-2",
  1501  			timeInMs:      400,
  1502  			expectedCount: 1,
  1503  			expectedSum:   0.4,
  1504  		},
  1505  	}
  1506  	for _, test := range testCases {
  1507  		pm := createMetricsForTesting()
  1508  		pm.RecordBidderServerResponseTime(time.Duration(test.timeInMs) * time.Millisecond)
  1509  
  1510  		m := dto.Metric{}
  1511  		pm.bidderServerResponseTimer.Write(&m)
  1512  		histogram := *m.GetHistogram()
  1513  
  1514  		assert.Equal(t, test.expectedCount, histogram.GetSampleCount())
  1515  		assert.Equal(t, test.expectedSum, histogram.GetSampleSum())
  1516  	}
  1517  }
  1518  
  1519  func TestRecordAdapterConnections(t *testing.T) {
  1520  	adapterName := openrtb_ext.BidderName("Adapter")
  1521  	lowerCasedAdapterName := "adapter"
  1522  
  1523  	type testIn struct {
  1524  		adapterName   openrtb_ext.BidderName
  1525  		connWasReused bool
  1526  		connWait      time.Duration
  1527  	}
  1528  
  1529  	type testOut struct {
  1530  		expectedConnReusedCount  int64
  1531  		expectedConnCreatedCount int64
  1532  		expectedConnWaitCount    uint64
  1533  		expectedConnWaitTime     float64
  1534  	}
  1535  
  1536  	testCases := []struct {
  1537  		description string
  1538  		in          testIn
  1539  		out         testOut
  1540  	}{
  1541  		{
  1542  			description: "[1] Successful, new connection created, was idle, has connection wait",
  1543  			in: testIn{
  1544  				adapterName:   adapterName,
  1545  				connWasReused: false,
  1546  				connWait:      time.Second * 5,
  1547  			},
  1548  			out: testOut{
  1549  				expectedConnReusedCount:  0,
  1550  				expectedConnCreatedCount: 1,
  1551  				expectedConnWaitCount:    1,
  1552  				expectedConnWaitTime:     5,
  1553  			},
  1554  		},
  1555  		{
  1556  			description: "[2] Successful, new connection created, not idle, has connection wait",
  1557  			in: testIn{
  1558  				adapterName:   adapterName,
  1559  				connWasReused: false,
  1560  				connWait:      time.Second * 4,
  1561  			},
  1562  			out: testOut{
  1563  				expectedConnReusedCount:  0,
  1564  				expectedConnCreatedCount: 1,
  1565  				expectedConnWaitCount:    1,
  1566  				expectedConnWaitTime:     4,
  1567  			},
  1568  		},
  1569  		{
  1570  			description: "[3] Successful, was reused, was idle, no connection wait",
  1571  			in: testIn{
  1572  				adapterName:   adapterName,
  1573  				connWasReused: true,
  1574  			},
  1575  			out: testOut{
  1576  				expectedConnReusedCount:  1,
  1577  				expectedConnCreatedCount: 0,
  1578  				expectedConnWaitCount:    1,
  1579  				expectedConnWaitTime:     0,
  1580  			},
  1581  		},
  1582  		{
  1583  			description: "[4] Successful, was reused, not idle, has connection wait",
  1584  			in: testIn{
  1585  				adapterName:   adapterName,
  1586  				connWasReused: true,
  1587  				connWait:      time.Second * 5,
  1588  			},
  1589  			out: testOut{
  1590  				expectedConnReusedCount:  1,
  1591  				expectedConnCreatedCount: 0,
  1592  				expectedConnWaitCount:    1,
  1593  				expectedConnWaitTime:     5,
  1594  			},
  1595  		},
  1596  	}
  1597  
  1598  	for i, test := range testCases {
  1599  		m := createMetricsForTesting()
  1600  		assertDesciptions := []string{
  1601  			fmt.Sprintf("[%d] Metric: adapterReusedConnections; Desc: %s", i+1, test.description),
  1602  			fmt.Sprintf("[%d] Metric: adapterCreatedConnections; Desc: %s", i+1, test.description),
  1603  			fmt.Sprintf("[%d] Metric: adapterWaitConnectionCount; Desc: %s", i+1, test.description),
  1604  			fmt.Sprintf("[%d] Metric: adapterWaitConnectionTime; Desc: %s", i+1, test.description),
  1605  		}
  1606  
  1607  		m.RecordAdapterConnections(test.in.adapterName, test.in.connWasReused, test.in.connWait)
  1608  
  1609  		// Assert number of reused connections
  1610  		assertCounterVecValue(t,
  1611  			assertDesciptions[0],
  1612  			"adapter_connection_reused",
  1613  			m.adapterReusedConnections,
  1614  			float64(test.out.expectedConnReusedCount),
  1615  			prometheus.Labels{adapterLabel: lowerCasedAdapterName})
  1616  
  1617  		// Assert number of new created connections
  1618  		assertCounterVecValue(t,
  1619  			assertDesciptions[1],
  1620  			"adapter_connection_created",
  1621  			m.adapterCreatedConnections,
  1622  			float64(test.out.expectedConnCreatedCount),
  1623  			prometheus.Labels{adapterLabel: lowerCasedAdapterName})
  1624  
  1625  		// Assert connection wait time
  1626  		histogram := getHistogramFromHistogramVec(m.adapterConnectionWaitTime, adapterLabel, lowerCasedAdapterName)
  1627  		assert.Equal(t, test.out.expectedConnWaitCount, histogram.GetSampleCount(), assertDesciptions[2])
  1628  		assert.Equal(t, test.out.expectedConnWaitTime, histogram.GetSampleSum(), assertDesciptions[3])
  1629  	}
  1630  }
  1631  
  1632  func TestDisabledMetrics(t *testing.T) {
  1633  	prometheusMetrics := NewMetrics(config.PrometheusMetrics{
  1634  		Port:      8080,
  1635  		Namespace: "prebid",
  1636  		Subsystem: "server",
  1637  	}, config.DisabledMetrics{
  1638  		AdapterBuyerUIDScrubbed:   true,
  1639  		AdapterConnectionMetrics:  true,
  1640  		AdapterGDPRRequestBlocked: true,
  1641  	},
  1642  		nil, nil)
  1643  
  1644  	// Assert counter vector was not initialized
  1645  	assert.Nil(t, prometheusMetrics.adapterReusedConnections, "Counter Vector adapterReusedConnections should be nil")
  1646  	assert.Nil(t, prometheusMetrics.adapterScrubbedBuyerUIDs, "Counter Vector adapterScrubbedBuyerUIDs should be nil")
  1647  	assert.Nil(t, prometheusMetrics.adapterCreatedConnections, "Counter Vector adapterCreatedConnections should be nil")
  1648  	assert.Nil(t, prometheusMetrics.adapterConnectionWaitTime, "Counter Vector adapterConnectionWaitTime should be nil")
  1649  	assert.Nil(t, prometheusMetrics.adapterGDPRBlockedRequests, "Counter Vector adapterGDPRBlockedRequests should be nil")
  1650  }
  1651  
  1652  func TestRecordRequestPrivacy(t *testing.T) {
  1653  	m := createMetricsForTesting()
  1654  
  1655  	// CCPA
  1656  	m.RecordRequestPrivacy(metrics.PrivacyLabels{
  1657  		CCPAEnforced: true,
  1658  		CCPAProvided: true,
  1659  	})
  1660  	m.RecordRequestPrivacy(metrics.PrivacyLabels{
  1661  		CCPAEnforced: true,
  1662  		CCPAProvided: false,
  1663  	})
  1664  	m.RecordRequestPrivacy(metrics.PrivacyLabels{
  1665  		CCPAEnforced: false,
  1666  		CCPAProvided: true,
  1667  	})
  1668  
  1669  	// COPPA
  1670  	m.RecordRequestPrivacy(metrics.PrivacyLabels{
  1671  		COPPAEnforced: true,
  1672  	})
  1673  
  1674  	// LMT
  1675  	m.RecordRequestPrivacy(metrics.PrivacyLabels{
  1676  		LMTEnforced: true,
  1677  	})
  1678  
  1679  	// GDPR
  1680  	m.RecordRequestPrivacy(metrics.PrivacyLabels{
  1681  		GDPREnforced:   true,
  1682  		GDPRTCFVersion: metrics.TCFVersionErr,
  1683  	})
  1684  	m.RecordRequestPrivacy(metrics.PrivacyLabels{
  1685  		GDPREnforced:   true,
  1686  		GDPRTCFVersion: metrics.TCFVersionV2,
  1687  	})
  1688  
  1689  	assertCounterVecValue(t, "", "privacy_ccpa", m.privacyCCPA,
  1690  		float64(1),
  1691  		prometheus.Labels{
  1692  			sourceLabel: sourceRequest,
  1693  			optOutLabel: "true",
  1694  		})
  1695  
  1696  	assertCounterVecValue(t, "", "privacy_ccpa", m.privacyCCPA,
  1697  		float64(1),
  1698  		prometheus.Labels{
  1699  			sourceLabel: sourceRequest,
  1700  			optOutLabel: "false",
  1701  		})
  1702  
  1703  	assertCounterVecValue(t, "", "privacy_coppa", m.privacyCOPPA,
  1704  		float64(1),
  1705  		prometheus.Labels{
  1706  			sourceLabel: sourceRequest,
  1707  		})
  1708  
  1709  	assertCounterVecValue(t, "", "privacy_lmt", m.privacyLMT,
  1710  		float64(1),
  1711  		prometheus.Labels{
  1712  			sourceLabel: sourceRequest,
  1713  		})
  1714  
  1715  	assertCounterVecValue(t, "", "privacy_tcf:err", m.privacyTCF,
  1716  		float64(1),
  1717  		prometheus.Labels{
  1718  			sourceLabel:  sourceRequest,
  1719  			versionLabel: "err",
  1720  		})
  1721  
  1722  	assertCounterVecValue(t, "", "privacy_tcf:v2", m.privacyTCF,
  1723  		float64(1),
  1724  		prometheus.Labels{
  1725  			sourceLabel:  sourceRequest,
  1726  			versionLabel: "v2",
  1727  		})
  1728  }
  1729  
  1730  func assertCounterValue(t *testing.T, description, name string, counter prometheus.Counter, expected float64) {
  1731  	m := dto.Metric{}
  1732  	counter.Write(&m)
  1733  	actual := *m.GetCounter().Value
  1734  
  1735  	assert.Equal(t, expected, actual, description)
  1736  }
  1737  
  1738  func assertCounterVecValue(t *testing.T, description, name string, counterVec *prometheus.CounterVec, expected float64, labels prometheus.Labels) {
  1739  	counter := counterVec.With(labels)
  1740  	assertCounterValue(t, description, name, counter, expected)
  1741  }
  1742  
  1743  func getHistogramFromHistogramVec(histogram *prometheus.HistogramVec, labelKey, labelValue string) dto.Histogram {
  1744  	var result dto.Histogram
  1745  	processMetrics(histogram, func(m dto.Metric) {
  1746  		for _, label := range m.GetLabel() {
  1747  			if label.GetName() == labelKey && label.GetValue() == labelValue {
  1748  				result = *m.GetHistogram()
  1749  			}
  1750  		}
  1751  	})
  1752  	return result
  1753  }
  1754  
  1755  func getHistogramFromHistogramVecByTwoKeys(histogram *prometheus.HistogramVec, label1Key, label1Value, label2Key, label2Value string) dto.Histogram {
  1756  	var result dto.Histogram
  1757  	processMetrics(histogram, func(m dto.Metric) {
  1758  		for ind, label := range m.GetLabel() {
  1759  			if label.GetName() == label1Key && label.GetValue() == label1Value {
  1760  				valInd := ind
  1761  				if ind == 1 {
  1762  					valInd = 0
  1763  				} else {
  1764  					valInd = 1
  1765  				}
  1766  				if m.Label[valInd].GetName() == label2Key && m.Label[valInd].GetValue() == label2Value {
  1767  					result = *m.GetHistogram()
  1768  				}
  1769  			}
  1770  		}
  1771  	})
  1772  	return result
  1773  }
  1774  
  1775  func processMetrics(collector prometheus.Collector, handler func(m dto.Metric)) {
  1776  	collectorChan := make(chan prometheus.Metric)
  1777  	go func() {
  1778  		collector.Collect(collectorChan)
  1779  		close(collectorChan)
  1780  	}()
  1781  
  1782  	for metric := range collectorChan {
  1783  		dtoMetric := dto.Metric{}
  1784  		metric.Write(&dtoMetric)
  1785  		handler(dtoMetric)
  1786  	}
  1787  }
  1788  
  1789  func assertHistogram(t *testing.T, name string, histogram dto.Histogram, expectedCount uint64, expectedSum float64) {
  1790  	assert.Equal(t, expectedCount, histogram.GetSampleCount(), name+":count")
  1791  	assert.Equal(t, expectedSum, histogram.GetSampleSum(), name+":sum")
  1792  }
  1793  
  1794  func TestRecordAdapterBuyerUIDScrubbed(t *testing.T) {
  1795  
  1796  	tests := []struct {
  1797  		name          string
  1798  		disabled      bool
  1799  		expectedCount float64
  1800  	}{
  1801  		{
  1802  			name:          "enabled",
  1803  			disabled:      false,
  1804  			expectedCount: 1,
  1805  		},
  1806  		{
  1807  			name:          "disabled",
  1808  			disabled:      true,
  1809  			expectedCount: 0,
  1810  		},
  1811  	}
  1812  
  1813  	for _, tt := range tests {
  1814  		t.Run(tt.name, func(t *testing.T) {
  1815  			m := createMetricsForTesting()
  1816  			m.metricsDisabled.AdapterBuyerUIDScrubbed = tt.disabled
  1817  			adapterName := openrtb_ext.BidderName("AnyName")
  1818  			lowerCasedAdapterName := "anyname"
  1819  			m.RecordAdapterBuyerUIDScrubbed(adapterName)
  1820  
  1821  			assertCounterVecValue(t,
  1822  				"Increment adapter buyeruid scrubbed counter",
  1823  				"adapter_buyeruids_scrubbed",
  1824  				m.adapterScrubbedBuyerUIDs,
  1825  				tt.expectedCount,
  1826  				prometheus.Labels{
  1827  					adapterLabel: lowerCasedAdapterName,
  1828  				})
  1829  		})
  1830  	}
  1831  }
  1832  
  1833  func TestRecordAdapterGDPRRequestBlocked(t *testing.T) {
  1834  	m := createMetricsForTesting()
  1835  	adapterName := openrtb_ext.BidderName("AnyName")
  1836  	lowerCasedAdapterName := "anyname"
  1837  	m.RecordAdapterGDPRRequestBlocked(adapterName)
  1838  
  1839  	assertCounterVecValue(t,
  1840  		"Increment adapter GDPR request blocked counter",
  1841  		"adapter_gdpr_requests_blocked",
  1842  		m.adapterGDPRBlockedRequests,
  1843  		1,
  1844  		prometheus.Labels{
  1845  			adapterLabel: lowerCasedAdapterName,
  1846  		})
  1847  }
  1848  
  1849  func TestStoredResponsesMetric(t *testing.T) {
  1850  	testCases := []struct {
  1851  		description                           string
  1852  		publisherId                           string
  1853  		accountStoredResponsesMetricsDisabled bool
  1854  		expectedAccountStoredResponsesCount   float64
  1855  		expectedStoredResponsesCount          float64
  1856  	}{
  1857  
  1858  		{
  1859  			description:                           "Publisher id is given, account stored responses enabled, expected both account stored responses and stored responses counter to have a record",
  1860  			publisherId:                           "acct-id",
  1861  			accountStoredResponsesMetricsDisabled: false,
  1862  			expectedAccountStoredResponsesCount:   1,
  1863  			expectedStoredResponsesCount:          1,
  1864  		},
  1865  		{
  1866  			description:                           "Publisher id is given, account stored responses disabled, expected stored responses counter only to have a record",
  1867  			publisherId:                           "acct-id",
  1868  			accountStoredResponsesMetricsDisabled: true,
  1869  			expectedAccountStoredResponsesCount:   0,
  1870  			expectedStoredResponsesCount:          1,
  1871  		},
  1872  		{
  1873  			description:                           "Publisher id is unknown, account stored responses enabled, expected stored responses counter only to have a record",
  1874  			publisherId:                           metrics.PublisherUnknown,
  1875  			accountStoredResponsesMetricsDisabled: true,
  1876  			expectedAccountStoredResponsesCount:   0,
  1877  			expectedStoredResponsesCount:          1,
  1878  		},
  1879  		{
  1880  			description:                           "Publisher id is unknown, account stored responses disabled, expected stored responses counter only to have a record",
  1881  			publisherId:                           metrics.PublisherUnknown,
  1882  			accountStoredResponsesMetricsDisabled: false,
  1883  			expectedAccountStoredResponsesCount:   0,
  1884  			expectedStoredResponsesCount:          1,
  1885  		},
  1886  	}
  1887  
  1888  	for _, test := range testCases {
  1889  		m := createMetricsForTesting()
  1890  		m.metricsDisabled.AccountStoredResponses = test.accountStoredResponsesMetricsDisabled
  1891  		m.RecordStoredResponse(test.publisherId)
  1892  
  1893  		assertCounterVecValue(t, "", "account stored responses", m.accountStoredResponses, test.expectedAccountStoredResponsesCount, prometheus.Labels{accountLabel: "acct-id"})
  1894  		assertCounterValue(t, "", "stored responses", m.storedResponses, test.expectedStoredResponsesCount)
  1895  	}
  1896  }
  1897  
  1898  func TestRecordAdsCertReqMetric(t *testing.T) {
  1899  	testCases := []struct {
  1900  		description                  string
  1901  		requestSuccess               bool
  1902  		expectedSuccessRequestsCount float64
  1903  		expectedFailedRequestsCount  float64
  1904  	}{
  1905  		{
  1906  			description:                  "Record failed request, expected success request count is 0 and failed request count is 1",
  1907  			requestSuccess:               false,
  1908  			expectedSuccessRequestsCount: 0,
  1909  			expectedFailedRequestsCount:  1,
  1910  		},
  1911  		{
  1912  			description:                  "Record successful request, expected success request count is 1 and failed request count is 0",
  1913  			requestSuccess:               true,
  1914  			expectedSuccessRequestsCount: 1,
  1915  			expectedFailedRequestsCount:  0,
  1916  		},
  1917  	}
  1918  
  1919  	for _, test := range testCases {
  1920  		m := createMetricsForTesting()
  1921  		m.RecordAdsCertReq(test.requestSuccess)
  1922  		assertCounterVecValue(t, test.description, "successfully signed requests", m.adsCertRequests, test.expectedSuccessRequestsCount, prometheus.Labels{successLabel: requestSuccessful})
  1923  		assertCounterVecValue(t, test.description, "unsuccessfully signed requests", m.adsCertRequests, test.expectedFailedRequestsCount, prometheus.Labels{successLabel: requestFailed})
  1924  	}
  1925  }
  1926  
  1927  func TestRecordAdsCertSignTime(t *testing.T) {
  1928  	type testIn struct {
  1929  		adsCertSignDuration time.Duration
  1930  	}
  1931  	type testOut struct {
  1932  		expDuration float64
  1933  		expCount    uint64
  1934  	}
  1935  	testCases := []struct {
  1936  		description string
  1937  		in          testIn
  1938  		out         testOut
  1939  	}{
  1940  		{
  1941  			description: "Five second AdsCert sign time",
  1942  			in: testIn{
  1943  				adsCertSignDuration: time.Second * 5,
  1944  			},
  1945  			out: testOut{
  1946  				expDuration: 5,
  1947  				expCount:    1,
  1948  			},
  1949  		},
  1950  		{
  1951  			description: "Five millisecond AdsCert sign time",
  1952  			in: testIn{
  1953  				adsCertSignDuration: time.Millisecond * 5,
  1954  			},
  1955  			out: testOut{
  1956  				expDuration: 0.005,
  1957  				expCount:    1,
  1958  			},
  1959  		},
  1960  		{
  1961  			description: "Zero AdsCert sign time",
  1962  			in:          testIn{},
  1963  			out: testOut{
  1964  				expDuration: 0,
  1965  				expCount:    1,
  1966  			},
  1967  		},
  1968  	}
  1969  	for i, test := range testCases {
  1970  		pm := createMetricsForTesting()
  1971  		pm.RecordAdsCertSignTime(test.in.adsCertSignDuration)
  1972  
  1973  		m := dto.Metric{}
  1974  		pm.adsCertSignTimer.Write(&m)
  1975  		histogram := *m.GetHistogram()
  1976  
  1977  		assert.Equal(t, test.out.expCount, histogram.GetSampleCount(), "[%d] Incorrect number of histogram entries. Desc: %s\n", i, test.description)
  1978  		assert.Equal(t, test.out.expDuration, histogram.GetSampleSum(), "[%d] Incorrect number of histogram cumulative values. Desc: %s\n", i, test.description)
  1979  	}
  1980  }
  1981  
  1982  func TestRecordModuleMetrics(t *testing.T) {
  1983  	m := createMetricsForTesting()
  1984  
  1985  	// check that each module has its own metric recorded with correct stage labels
  1986  	for module, stages := range modulesStages {
  1987  		for _, stage := range stages {
  1988  			// first record the metrics
  1989  			m.RecordModuleCalled(metrics.ModuleLabels{
  1990  				Module: module,
  1991  				Stage:  stage,
  1992  			}, time.Millisecond*1)
  1993  			m.RecordModuleFailed(metrics.ModuleLabels{
  1994  				Module: module,
  1995  				Stage:  stage,
  1996  			})
  1997  			m.RecordModuleSuccessNooped(metrics.ModuleLabels{
  1998  				Module: module,
  1999  				Stage:  stage,
  2000  			})
  2001  			m.RecordModuleSuccessUpdated(metrics.ModuleLabels{
  2002  				Module: module,
  2003  				Stage:  stage,
  2004  			})
  2005  			m.RecordModuleSuccessRejected(metrics.ModuleLabels{
  2006  				Module: module,
  2007  				Stage:  stage,
  2008  			})
  2009  			m.RecordModuleExecutionError(metrics.ModuleLabels{
  2010  				Module: module,
  2011  				Stage:  stage,
  2012  			})
  2013  			m.RecordModuleTimeout(metrics.ModuleLabels{
  2014  				Module: module,
  2015  				Stage:  stage,
  2016  			})
  2017  
  2018  			// now check that the values are correct
  2019  			result := getHistogramFromHistogramVec(m.moduleDuration[module], stageLabel, stage)
  2020  			assertHistogram(t, fmt.Sprintf("module_%s_duration", module), result, 1, 0.001)
  2021  			assertCounterVecValue(t, "Module calls performed", fmt.Sprintf("%s metric recorded during %s stage", module, stage), m.moduleCalls[module], 1, prometheus.Labels{stageLabel: stage})
  2022  			assertCounterVecValue(t, "Module calls failed", fmt.Sprintf("%s metric recorded during %s stage", module, stage), m.moduleFailures[module], 1, prometheus.Labels{stageLabel: stage})
  2023  			assertCounterVecValue(t, "Module success noop action", fmt.Sprintf("%s metric recorded during %s stage", module, stage), m.moduleSuccessNoops[module], 1, prometheus.Labels{stageLabel: stage})
  2024  			assertCounterVecValue(t, "Module success update action", fmt.Sprintf("%s metric recorded during %s stage", module, stage), m.moduleSuccessUpdates[module], 1, prometheus.Labels{stageLabel: stage})
  2025  			assertCounterVecValue(t, "Module success reject action", fmt.Sprintf("%s metric recorded during %s stage", module, stage), m.moduleSuccessRejects[module], 1, prometheus.Labels{stageLabel: stage})
  2026  			assertCounterVecValue(t, "Module execution error", fmt.Sprintf("%s metric recorded during %s stage", module, stage), m.moduleExecutionErrors[module], 1, prometheus.Labels{stageLabel: stage})
  2027  			assertCounterVecValue(t, "Module timeout", fmt.Sprintf("%s metric recorded during %s stage", module, stage), m.moduleTimeouts[module], 1, prometheus.Labels{stageLabel: stage})
  2028  		}
  2029  	}
  2030  }