SQL Expressions / Alerting: Do not allow duplicates (#103394)

This commit is contained in:
Kyle Brandt
2025-04-04 10:00:30 -04:00
committed by GitHub
parent 3766deed34
commit b1490a10e8
3 changed files with 164 additions and 12 deletions

View File

@ -1,6 +1,7 @@
package expr
import (
"fmt"
"testing"
"github.com/grafana/grafana-plugin-sdk-go/data"
@ -10,7 +11,6 @@ import (
func TestExtractNumberSetFromSQLForAlerting(t *testing.T) {
t.Run("SingleRowNoLabels", func(t *testing.T) {
input := data.NewFrame("",
data.NewField(SQLMetricFieldName, nil, []string{"cpu"}), // will be treated as a label
data.NewField(SQLValueFieldName, nil, []*float64{fp(3.14)}),
)
@ -20,17 +20,15 @@ func TestExtractNumberSetFromSQLForAlerting(t *testing.T) {
got := numbers[0]
require.Equal(t, fp(3.14), got.GetFloat64Value())
require.Equal(t, data.Labels{
SQLMetricFieldName: "cpu",
}, got.GetLabels())
require.Equal(t, data.Labels{}, got.GetLabels())
})
t.Run("TwoRowsWithLabelsAndDisplay", func(t *testing.T) {
input := data.NewFrame("",
data.NewField(SQLMetricFieldName, nil, []string{"cpu", "cpu"}),
data.NewField(SQLValueFieldName, nil, []*float64{fp(1.0), fp(2.0)}),
data.NewField(SQLDisplayFieldName, nil, []*string{sp("CPU A"), sp("CPU A")}),
data.NewField("host", nil, []*string{sp("a"), sp("a")}),
data.NewField(SQLDisplayFieldName, nil, []*string{sp("CPU A"), sp("CPU B")}),
data.NewField("host", nil, []*string{sp("a"), sp("b")}),
)
numbers, err := extractNumberSetFromSQLForAlerting(input)
@ -47,8 +45,8 @@ func TestExtractNumberSetFromSQLForAlerting(t *testing.T) {
require.Equal(t, fp(2.0), numbers[1].GetFloat64Value())
require.Equal(t, data.Labels{
SQLMetricFieldName: "cpu",
SQLDisplayFieldName: "CPU A",
"host": "a",
SQLDisplayFieldName: "CPU B",
"host": "b",
}, numbers[1].GetLabels())
})
@ -78,3 +76,85 @@ func TestExtractNumberSetFromSQLForAlerting(t *testing.T) {
}, numbers[1].GetLabels())
})
}
func TestExtractNumberSetFromSQLForAlerting_Duplicates(t *testing.T) {
t.Run("AllDuplicates_ReturnsError", func(t *testing.T) {
input := data.NewFrame("",
data.NewField(SQLMetricFieldName, nil, []string{"cpu", "cpu"}),
data.NewField(SQLValueFieldName, nil, []*float64{fp(1.0), fp(2.0)}),
data.NewField("host", nil, []*string{sp("a"), sp("a")}),
)
numbers, err := extractNumberSetFromSQLForAlerting(input)
require.Error(t, err)
require.Nil(t, numbers)
require.Contains(t, err.Error(), "duplicate values across the string columns")
require.Contains(t, err.Error(), "host=a")
require.Contains(t, err.Error(), "GROUP BY or aggregation")
})
t.Run("SomeDuplicates_ReturnsError", func(t *testing.T) {
input := data.NewFrame("",
data.NewField(SQLMetricFieldName, nil, []string{"cpu", "cpu", "cpu"}),
data.NewField(SQLValueFieldName, nil, []*float64{fp(1.0), fp(2.0), fp(3.0)}),
data.NewField("host", nil, []*string{sp("a"), sp("a"), sp("b")}),
)
numbers, err := extractNumberSetFromSQLForAlerting(input)
require.Error(t, err)
require.Nil(t, numbers)
require.Contains(t, err.Error(), "duplicate values across the string columns")
require.Contains(t, err.Error(), "host=a")
require.Contains(t, err.Error(), "GROUP BY or aggregation")
})
t.Run("NoDuplicates_Succeeds", func(t *testing.T) {
input := data.NewFrame("",
data.NewField(SQLMetricFieldName, nil, []string{"cpu", "cpu"}),
data.NewField(SQLValueFieldName, nil, []*float64{fp(1.0), fp(2.0)}),
data.NewField("host", nil, []*string{sp("a"), sp("b")}),
)
numbers, err := extractNumberSetFromSQLForAlerting(input)
require.NoError(t, err)
require.Len(t, numbers, 2)
require.Equal(t, data.Labels{
SQLMetricFieldName: "cpu",
"host": "a",
}, numbers[0].GetLabels())
require.Equal(t, data.Labels{
SQLMetricFieldName: "cpu",
"host": "b",
}, numbers[1].GetLabels())
})
t.Run("MoreThan10DuplicateSets_TruncatesErrorList", func(t *testing.T) {
const totalRows = 30
labels := make([]string, totalRows)
values := make([]*float64, totalRows)
hosts := make([]*string, totalRows)
for i := 0; i < totalRows; i++ {
labels[i] = "cpu"
values[i] = fp(float64(i + 1))
h := fmt.Sprintf("host%d", i%15) // 15 distinct combos, each duplicated
hosts[i] = &h
}
input := data.NewFrame("",
data.NewField(SQLMetricFieldName, nil, labels),
data.NewField(SQLValueFieldName, nil, values),
data.NewField("host", nil, hosts),
)
numbers, err := extractNumberSetFromSQLForAlerting(input)
require.Error(t, err)
require.Nil(t, numbers)
require.Contains(t, err.Error(), "duplicate values across the string columns")
require.Contains(t, err.Error(), "Examples:")
require.Contains(t, err.Error(), "... and 10 more")
require.Contains(t, err.Error(), "GROUP BY or aggregation")
})
}