mirror of
https://github.com/coder/coder.git
synced 2025-07-06 15:41:45 +00:00
fix: fix MetricsAggregator check for metric sameness (#11508)
Fixes #11451 A refactor of the Agent API passes metrics as protobufs, which include pointers to label name/value pairs. The aggregator tested for sameness by doing a shallow compare of label values, which for different stats reports would compare unequal because the pointers would be different. This fix does a deep compare. While testing I also noted that we neglect to compare template names. This is unlikely to have caused any issue in practice, since the combination of username/workspace is unique, but in the context of comparing metric labels we should do the comparison. If a user creates a workspace, deletes it, then recreates from a different template, we could in principle have reported incorrect stats for the old template.
This commit is contained in:
210
coderd/prometheusmetrics/aggregator_internal_test.go
Normal file
210
coderd/prometheusmetrics/aggregator_internal_test.go
Normal file
@ -0,0 +1,210 @@
|
||||
package prometheusmetrics
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/v2/agent/proto"
|
||||
)
|
||||
|
||||
func TestAnnotatedMetric_Is(t *testing.T) {
|
||||
t.Parallel()
|
||||
am1 := &annotatedMetric{
|
||||
Stats_Metric: &proto.Stats_Metric{
|
||||
Name: "met",
|
||||
Type: proto.Stats_Metric_COUNTER,
|
||||
Value: 1,
|
||||
Labels: []*proto.Stats_Metric_Label{
|
||||
{Name: "rarity", Value: "blue moon"},
|
||||
{Name: "certainty", Value: "yes"},
|
||||
},
|
||||
},
|
||||
username: "spike",
|
||||
workspaceName: "work",
|
||||
agentName: "janus",
|
||||
templateName: "tempe",
|
||||
expiryDate: time.Now(),
|
||||
}
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
req updateRequest
|
||||
m *proto.Stats_Metric
|
||||
is bool
|
||||
}{
|
||||
{
|
||||
name: "OK",
|
||||
req: updateRequest{
|
||||
username: "spike",
|
||||
workspaceName: "work",
|
||||
agentName: "janus",
|
||||
templateName: "tempe",
|
||||
metrics: nil,
|
||||
timestamp: time.Now().Add(-5 * time.Second),
|
||||
},
|
||||
m: &proto.Stats_Metric{
|
||||
Name: "met",
|
||||
Type: proto.Stats_Metric_COUNTER,
|
||||
Value: 2,
|
||||
Labels: []*proto.Stats_Metric_Label{
|
||||
{Name: "rarity", Value: "blue moon"},
|
||||
{Name: "certainty", Value: "yes"},
|
||||
},
|
||||
},
|
||||
is: true,
|
||||
},
|
||||
{
|
||||
name: "missingLabel",
|
||||
req: updateRequest{
|
||||
username: "spike",
|
||||
workspaceName: "work",
|
||||
agentName: "janus",
|
||||
templateName: "tempe",
|
||||
metrics: nil,
|
||||
timestamp: time.Now().Add(-5 * time.Second),
|
||||
},
|
||||
m: &proto.Stats_Metric{
|
||||
Name: "met",
|
||||
Type: proto.Stats_Metric_COUNTER,
|
||||
Value: 2,
|
||||
Labels: []*proto.Stats_Metric_Label{
|
||||
{Name: "certainty", Value: "yes"},
|
||||
},
|
||||
},
|
||||
is: false,
|
||||
},
|
||||
{
|
||||
name: "wrongLabelValue",
|
||||
req: updateRequest{
|
||||
username: "spike",
|
||||
workspaceName: "work",
|
||||
agentName: "janus",
|
||||
templateName: "tempe",
|
||||
metrics: nil,
|
||||
timestamp: time.Now().Add(-5 * time.Second),
|
||||
},
|
||||
m: &proto.Stats_Metric{
|
||||
Name: "met",
|
||||
Type: proto.Stats_Metric_COUNTER,
|
||||
Value: 2,
|
||||
Labels: []*proto.Stats_Metric_Label{
|
||||
{Name: "rarity", Value: "blue moon"},
|
||||
{Name: "certainty", Value: "inshallah"},
|
||||
},
|
||||
},
|
||||
is: false,
|
||||
},
|
||||
{
|
||||
name: "wrongMetricName",
|
||||
req: updateRequest{
|
||||
username: "spike",
|
||||
workspaceName: "work",
|
||||
agentName: "janus",
|
||||
templateName: "tempe",
|
||||
metrics: nil,
|
||||
timestamp: time.Now().Add(-5 * time.Second),
|
||||
},
|
||||
m: &proto.Stats_Metric{
|
||||
Name: "cub",
|
||||
Type: proto.Stats_Metric_COUNTER,
|
||||
Value: 2,
|
||||
Labels: []*proto.Stats_Metric_Label{
|
||||
{Name: "rarity", Value: "blue moon"},
|
||||
{Name: "certainty", Value: "yes"},
|
||||
},
|
||||
},
|
||||
is: false,
|
||||
},
|
||||
{
|
||||
name: "wrongUsername",
|
||||
req: updateRequest{
|
||||
username: "steve",
|
||||
workspaceName: "work",
|
||||
agentName: "janus",
|
||||
templateName: "tempe",
|
||||
metrics: nil,
|
||||
timestamp: time.Now().Add(-5 * time.Second),
|
||||
},
|
||||
m: &proto.Stats_Metric{
|
||||
Name: "met",
|
||||
Type: proto.Stats_Metric_COUNTER,
|
||||
Value: 2,
|
||||
Labels: []*proto.Stats_Metric_Label{
|
||||
{Name: "rarity", Value: "blue moon"},
|
||||
{Name: "certainty", Value: "yes"},
|
||||
},
|
||||
},
|
||||
is: false,
|
||||
},
|
||||
{
|
||||
name: "wrongWorkspaceName",
|
||||
req: updateRequest{
|
||||
username: "spike",
|
||||
workspaceName: "play",
|
||||
agentName: "janus",
|
||||
templateName: "tempe",
|
||||
metrics: nil,
|
||||
timestamp: time.Now().Add(-5 * time.Second),
|
||||
},
|
||||
m: &proto.Stats_Metric{
|
||||
Name: "met",
|
||||
Type: proto.Stats_Metric_COUNTER,
|
||||
Value: 2,
|
||||
Labels: []*proto.Stats_Metric_Label{
|
||||
{Name: "rarity", Value: "blue moon"},
|
||||
{Name: "certainty", Value: "yes"},
|
||||
},
|
||||
},
|
||||
is: false,
|
||||
},
|
||||
{
|
||||
name: "wrongAgentName",
|
||||
req: updateRequest{
|
||||
username: "spike",
|
||||
workspaceName: "work",
|
||||
agentName: "bond",
|
||||
templateName: "tempe",
|
||||
metrics: nil,
|
||||
timestamp: time.Now().Add(-5 * time.Second),
|
||||
},
|
||||
m: &proto.Stats_Metric{
|
||||
Name: "met",
|
||||
Type: proto.Stats_Metric_COUNTER,
|
||||
Value: 2,
|
||||
Labels: []*proto.Stats_Metric_Label{
|
||||
{Name: "rarity", Value: "blue moon"},
|
||||
{Name: "certainty", Value: "yes"},
|
||||
},
|
||||
},
|
||||
is: false,
|
||||
},
|
||||
{
|
||||
name: "wrongTemplateName",
|
||||
req: updateRequest{
|
||||
username: "spike",
|
||||
workspaceName: "work",
|
||||
agentName: "janus",
|
||||
templateName: "phoenix",
|
||||
metrics: nil,
|
||||
timestamp: time.Now().Add(-5 * time.Second),
|
||||
},
|
||||
m: &proto.Stats_Metric{
|
||||
Name: "met",
|
||||
Type: proto.Stats_Metric_COUNTER,
|
||||
Value: 2,
|
||||
Labels: []*proto.Stats_Metric_Label{
|
||||
{Name: "rarity", Value: "blue moon"},
|
||||
{Name: "certainty", Value: "yes"},
|
||||
},
|
||||
},
|
||||
is: false,
|
||||
},
|
||||
} {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.Equal(t, tc.is, am1.is(tc.req, tc.m))
|
||||
})
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user