observability_test.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. package solacereceiver
  4. import (
  5. "reflect"
  6. "testing"
  7. "github.com/stretchr/testify/assert"
  8. "github.com/stretchr/testify/require"
  9. "go.opencensus.io/stats"
  10. "go.opencensus.io/stats/view"
  11. )
  12. type metricsTestCase struct {
  13. fn func() // function to test updating metrics
  14. v *view.View // view to reference
  15. m stats.Measure // expected measure of the view
  16. calls int // number of times to call fn
  17. expected int // expected value of reported metric at end of calls
  18. }
  19. func TestRecordMetrics(t *testing.T) {
  20. metrics := newTestMetrics(t)
  21. testCases := []metricsTestCase{
  22. {metrics.recordFailedReconnection, metrics.views.failedReconnections, metrics.stats.failedReconnections, 3, 3},
  23. {metrics.recordRecoverableUnmarshallingError, metrics.views.recoverableUnmarshallingErrors, metrics.stats.recoverableUnmarshallingErrors, 3, 3},
  24. {metrics.recordFatalUnmarshallingError, metrics.views.fatalUnmarshallingErrors, metrics.stats.fatalUnmarshallingErrors, 3, 3},
  25. {metrics.recordDroppedSpanMessages, metrics.views.droppedSpanMessages, metrics.stats.droppedSpanMessages, 3, 3},
  26. {metrics.recordReceivedSpanMessages, metrics.views.receivedSpanMessages, metrics.stats.receivedSpanMessages, 3, 3},
  27. {func() {
  28. metrics.recordReportedSpans(2)
  29. }, metrics.views.reportedSpans, metrics.stats.reportedSpans, 3, 6},
  30. {func() {
  31. metrics.recordReceiverStatus(receiverStateTerminated)
  32. }, metrics.views.receiverStatus, metrics.stats.receiverStatus, 3, int(receiverStateTerminated)},
  33. {metrics.recordNeedUpgrade, metrics.views.needUpgrade, metrics.stats.needUpgrade, 3, 1},
  34. {func() {
  35. metrics.recordFlowControlStatus(flowControlStateControlled)
  36. }, metrics.views.flowControlStatus, metrics.stats.flowControlStatus, 3, 1},
  37. {func() {
  38. metrics.recordFlowControlRecentRetries(5)
  39. }, metrics.views.flowControlRecentRetries, metrics.stats.flowControlRecentRetries, 3, 5},
  40. {metrics.recordFlowControlTotal, metrics.views.flowControlTotal, metrics.stats.flowControlTotal, 3, 3},
  41. {metrics.recordFlowControlSingleSuccess, metrics.views.flowControlSingleSuccess, metrics.stats.flowControlSingleSuccess, 3, 3},
  42. {metrics.recordDroppedEgressSpan, metrics.views.droppedEgressSpans, metrics.stats.droppedEgressSpans, 3, 3},
  43. }
  44. for _, tc := range testCases {
  45. t.Run(tc.m.Name(), func(t *testing.T) {
  46. for i := 0; i < tc.calls; i++ {
  47. tc.fn()
  48. }
  49. validateMetric(t, tc.v, tc.expected)
  50. })
  51. }
  52. }
  53. func validateMetric(t *testing.T, v *view.View, expected any) {
  54. // hack to reset stats to 0
  55. defer func() {
  56. view.Unregister(v)
  57. err := view.Register(v)
  58. assert.NoError(t, err)
  59. }()
  60. rows, err := view.RetrieveData(v.Name)
  61. assert.NoError(t, err)
  62. if expected != nil {
  63. require.Len(t, rows, 1)
  64. value := reflect.Indirect(reflect.ValueOf(rows[0].Data)).FieldByName("Value").Interface()
  65. assert.EqualValues(t, expected, value)
  66. } else {
  67. assert.Len(t, rows, 0)
  68. }
  69. }
  70. // TestRegisterViewsExpectingFailure validates that if an error is returned from view.Register, we panic and don't continue with initialization
  71. func TestRegisterViewsExpectingFailure(t *testing.T) {
  72. statName := "solacereceiver/" + t.Name() + "/failed_reconnections"
  73. stat := stats.Int64(statName, "", stats.UnitDimensionless)
  74. err := view.Register(&view.View{
  75. Name: buildReceiverCustomMetricName(statName),
  76. Description: "some description",
  77. Measure: stat,
  78. Aggregation: view.Sum(),
  79. })
  80. require.NoError(t, err)
  81. metrics, err := newOpenCensusMetrics(t.Name())
  82. assert.Error(t, err)
  83. assert.Nil(t, metrics)
  84. }
  85. // newTestMetrics builds a new metrics that will cleanup when testing.T completes
  86. func newTestMetrics(t *testing.T) *opencensusMetrics {
  87. m, err := newOpenCensusMetrics(t.Name())
  88. require.NoError(t, err)
  89. t.Cleanup(func() {
  90. unregisterMetrics(m)
  91. })
  92. return m
  93. }
  94. // unregisterMetrics is used to unregister the metrics for testing purposes
  95. func unregisterMetrics(metrics *opencensusMetrics) {
  96. view.Unregister(
  97. metrics.views.failedReconnections,
  98. metrics.views.recoverableUnmarshallingErrors,
  99. metrics.views.fatalUnmarshallingErrors,
  100. metrics.views.droppedSpanMessages,
  101. metrics.views.receivedSpanMessages,
  102. metrics.views.reportedSpans,
  103. metrics.views.receiverStatus,
  104. metrics.views.needUpgrade,
  105. )
  106. }