Skip to content

Commit

Permalink
Add metric tests
Browse files Browse the repository at this point in the history
  • Loading branch information
hugoShaka committed Jan 8, 2025
1 parent 13f9beb commit 37ff41f
Show file tree
Hide file tree
Showing 2 changed files with 260 additions and 4 deletions.
3 changes: 1 addition & 2 deletions lib/autoupdate/rollout/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ func (m *metrics) setGroupStates(groups []*autoupdatepb.AutoUpdateAgentRolloutSt
}

// If we have less groups than before, we must unset the metrics for higher group numbers.
for i := len(groups); i <= m.groupCount; i++ {
for i := len(groups); i < m.groupCount; i++ {
labels := prometheus.Labels{metricsGroupNumberLabelName: strconv.Itoa(i)}
m.rolloutGroupState.With(labels).Set(float64(0))
}
Expand All @@ -322,7 +322,6 @@ func (m *metrics) observeRollout(rollout *autoupdatepb.AutoUpdateAgentRollout, n
m.rolloutMode.Set(float64(agentModeCode[rollout.GetSpec().GetAutoupdateMode()]))
m.setVersionMetric(rollout.GetSpec().GetStartVersion(), m.rolloutStart, now)
m.setVersionMetric(rollout.GetSpec().GetTargetVersion(), m.rolloutTarget, now)

}

if to := rollout.GetStatus().GetTimeOverride().AsTime(); !(to.IsZero() || to.Unix() == 0) {
Expand Down
261 changes: 259 additions & 2 deletions lib/autoupdate/rollout/metrics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,269 @@
package rollout

import (
"testing"

autoupdatepb "github.com/gravitational/teleport/api/gen/proto/go/teleport/autoupdate/v1"
"github.com/jonboulle/clockwork"
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
"github.com/stretchr/testify/require"
"testing"
"time"
)

func newMetricsForTest(t *testing.T) *metrics {
reg := prometheus.NewRegistry()
return newMetrics(reg)
}

func Test_setVersionMetric(t *testing.T) {
now := clockwork.NewFakeClock().Now()
aMinuteAgo := now.Add(-time.Minute)
aWeekAgo := now.Add(-time.Hour * 24 * 7)
testVersion := "1.2.3-alpha.1"
previousVersion := "1.2.1"
testMetricLabels := []string{metricsVersionLabelName}
tests := []struct {
name string
previousVersions map[string]time.Time
previousMetrics map[string]float64
expectedVersions map[string]time.Time
expectedMetrics map[string]float64
}{
{
name: "no versions",
previousVersions: map[string]time.Time{},
previousMetrics: map[string]float64{},
expectedVersions: map[string]time.Time{
testVersion: now,
},
expectedMetrics: map[string]float64{
testVersion: 1,
},
},
{
name: "same version, not expired",
previousVersions: map[string]time.Time{
testVersion: aMinuteAgo,
},
previousMetrics: map[string]float64{
testVersion: 1,
},
expectedVersions: map[string]time.Time{
testVersion: now,
},
expectedMetrics: map[string]float64{
testVersion: 1,
},
},
{
name: "same version, expired",
previousVersions: map[string]time.Time{
testVersion: aWeekAgo,
},
previousMetrics: map[string]float64{
testVersion: 1,
},
expectedVersions: map[string]time.Time{
testVersion: now,
},
expectedMetrics: map[string]float64{
testVersion: 1,
},
},
{
name: "old non-expired versions",
previousVersions: map[string]time.Time{
previousVersion: aMinuteAgo,
},
previousMetrics: map[string]float64{
previousVersion: 1,
},
expectedVersions: map[string]time.Time{
previousVersion: aMinuteAgo,
testVersion: now,
},
expectedMetrics: map[string]float64{
previousVersion: 0,
testVersion: 1,
},
},
{
name: "old expired versions",
previousVersions: map[string]time.Time{
previousVersion: aWeekAgo,
},
previousMetrics: map[string]float64{
previousVersion: 1,
},
expectedVersions: map[string]time.Time{
testVersion: now,
},
expectedMetrics: map[string]float64{
testVersion: 1,
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
t.Parallel()
// Test setup: create metrics and load previous metrics.
m := metrics{
previousVersions: test.previousVersions,
}

testGauge := prometheus.NewGaugeVec(prometheus.GaugeOpts{}, testMetricLabels)
for k, v := range test.previousMetrics {
testGauge.With(prometheus.Labels{testMetricLabels[0]: k}).Set(v)
}

// Test execution: set the version metric.
m.setVersionMetric(testVersion, testGauge, now)

// Test validation: collect the metrics and check that the state match what we expect.
require.Equal(t, test.expectedVersions, m.previousVersions)
metricsChan := make(chan prometheus.Metric, 100)
testGauge.Collect(metricsChan)
close(metricsChan)
metricsResult := collectMetricsByLabel(t, metricsChan, testMetricLabels[0])
require.Equal(t, test.expectedMetrics, metricsResult)
})
}
}

func Test_setGroupStates(t *testing.T) {
testMetricLabels := []string{metricsGroupNumberLabelName}
testGroups := []*autoupdatepb.AutoUpdateAgentRolloutStatusGroup{
{State: autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_DONE},
{State: autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_ACTIVE},
{State: autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_UNSTARTED},
}
tests := []struct {
name string
previousGroupCount int
previousMetrics map[string]float64
expectedGroupCount int
expectedMetrics map[string]float64
}{
{
name: "no groups",
previousGroupCount: 0,
previousMetrics: map[string]float64{},
expectedGroupCount: len(testGroups),
expectedMetrics: map[string]float64{
"0": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_DONE),
"1": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_ACTIVE),
"2": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_UNSTARTED),
},
},
{
name: "same groups, same states",
previousGroupCount: len(testGroups),
previousMetrics: map[string]float64{
"0": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_DONE),
"1": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_ACTIVE),
"2": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_UNSTARTED),
},
expectedGroupCount: len(testGroups),
expectedMetrics: map[string]float64{
"0": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_DONE),
"1": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_ACTIVE),
"2": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_UNSTARTED),
},
},
{
name: "same groups, different states",
previousGroupCount: len(testGroups),
previousMetrics: map[string]float64{
"0": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_ACTIVE),
"1": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_UNSTARTED),
"2": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_UNSTARTED),
},
expectedGroupCount: len(testGroups),
expectedMetrics: map[string]float64{
"0": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_DONE),
"1": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_ACTIVE),
"2": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_UNSTARTED),
},
},
{
name: "less groups",
previousGroupCount: 1,
previousMetrics: map[string]float64{
"0": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_DONE),
},
expectedGroupCount: len(testGroups),
expectedMetrics: map[string]float64{
"0": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_DONE),
"1": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_ACTIVE),
"2": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_UNSTARTED),
},
},
{
name: "more groups",
previousGroupCount: 5,
previousMetrics: map[string]float64{
"0": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_ACTIVE),
"1": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_UNSTARTED),
"2": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_UNSTARTED),
"3": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_UNSTARTED),
"4": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_UNSTARTED),
},
expectedGroupCount: len(testGroups),
expectedMetrics: map[string]float64{
"0": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_DONE),
"1": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_ACTIVE),
"2": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_UNSTARTED),
"3": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_UNSPECIFIED),
"4": float64(autoupdatepb.AutoUpdateAgentGroupState_AUTO_UPDATE_AGENT_GROUP_STATE_UNSPECIFIED),
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
t.Parallel()

testGauge := prometheus.NewGaugeVec(prometheus.GaugeOpts{}, testMetricLabels)
for k, v := range test.previousMetrics {
testGauge.With(prometheus.Labels{testMetricLabels[0]: k}).Set(v)
}

// Test setup: create metrics and load previous metrics.
m := metrics{
groupCount: test.previousGroupCount,
rolloutGroupState: testGauge,
}

// Test execution: set the version metric.
m.setGroupStates(testGroups)

// Test validation: collect the metrics and check that the state match what we expect.
require.Equal(t, test.expectedGroupCount, m.groupCount)
metricsChan := make(chan prometheus.Metric, 100)
m.rolloutGroupState.Collect(metricsChan)
close(metricsChan)
metricsResult := collectMetricsByLabel(t, metricsChan, testMetricLabels[0])
require.Equal(t, test.expectedMetrics, metricsResult)

})
}
}

func collectMetricsByLabel(t *testing.T, ch <-chan prometheus.Metric, labelName string) map[string]float64 {
t.Helper()
result := make(map[string]float64)

var protoMetric dto.Metric
for {
m, ok := <-ch
if !ok {
return result
}
require.NoError(t, m.Write(&protoMetric))
ll := protoMetric.GetLabel()
require.Len(t, ll, 1)
require.Equal(t, labelName, ll[0].GetName())
gg := protoMetric.GetGauge()
require.NotNil(t, gg)
result[ll[0].GetValue()] = gg.GetValue()
}
}

0 comments on commit 37ff41f

Please sign in to comment.