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