The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/util/cmputil/reporter_test.go

203 lines
4.9 KiB

package cmputil
import (
"math/rand"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/util"
)
type subStruct struct {
Data any
}
type testStruct struct {
Number float64
NumberPtr *float64
Text string
TextPtr *string
Flag bool
FlagPtr *bool
Dict map[float64]float64
Slice []float64
SubStruct subStruct
SubStructPtr *subStruct
}
func testStructDiff(left, right testStruct) DiffReport {
var reporter DiffReporter
ops := make([]cmp.Option, 0, 4)
ops = append(ops, cmp.Reporter(&reporter))
cmp.Equal(left, right, ops...)
return reporter.Diffs
}
func TestIsAddedDeleted_Collections(t *testing.T) {
testCases := []struct {
name string
left testStruct
right testStruct
field string
}{
{
name: "nil vs non-empty slice",
left: testStruct{
Slice: nil,
},
right: testStruct{
Slice: []float64{rand.Float64()},
},
field: "Slice",
},
{
name: "empty vs non-empty slice",
left: testStruct{
Slice: []float64{},
},
right: testStruct{
Slice: []float64{rand.Float64()},
},
field: "Slice",
},
{
name: "nil vs non-empty map",
left: testStruct{
Dict: nil,
},
right: testStruct{
Dict: map[float64]float64{rand.Float64(): rand.Float64()},
},
field: "Slice",
},
{
name: "empty vs non-empty map",
left: testStruct{
Dict: map[float64]float64{},
},
right: testStruct{
Dict: map[float64]float64{rand.Float64(): rand.Float64()},
},
field: "Slice",
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
left := testCase.left
right := testCase.right
field := testCase.field
t.Run("IsAddOperation=true, IsDeleted=false", func(t *testing.T) {
diff := testStructDiff(left, right)
require.Lenf(t, diff, 1, "diff was expected to have only one field %s but got %v", field, diff.String())
require.Len(t, diff.Paths(), 1)
d := diff[0]
require.Truef(t, d.IsAddOperation(), "diff %v should be treated as Add operation but it wasn't", d)
require.Falsef(t, d.IsDeleteOperation(), "diff %v should not be treated as Delete operation but it was", d)
})
t.Run("IsDeleted=true, IsAddOperation=false", func(t *testing.T) {
diff := testStructDiff(right, left)
require.Lenf(t, diff, 1, "diff was expected to have only one field %s but got %v", field, diff.String())
require.Len(t, diff.Paths(), 1)
d := diff[0]
require.Truef(t, d.IsDeleteOperation(), "diff %v should be treated as Delete operation but it wasn't", d)
require.Falsef(t, d.IsAddOperation(), "diff %v should not be treated as Delete operation but it was", d)
})
})
}
t.Run("IsAddOperation=false, IsDeleted=false if changes in struct fields", func(t *testing.T) {
left := testStruct{}
right := testStruct{
Number: rand.Float64(),
NumberPtr: util.Pointer(rand.Float64()),
Text: util.GenerateShortUID(),
TextPtr: util.Pointer(util.GenerateShortUID()),
Flag: true,
FlagPtr: util.Pointer(true),
SubStruct: subStruct{
Data: rand.Float64(),
},
SubStructPtr: &subStruct{Data: rand.Float64()},
}
diff := testStructDiff(left, right)
require.Len(t, diff, 8)
require.Len(t, diff.Paths(), 8)
for _, d := range diff {
assert.Falsef(t, d.IsAddOperation(), "diff %v was not supposed to be Add operation", d.String())
assert.Falsef(t, d.IsDeleteOperation(), "diff %v was not supposed to be Delete operation", d.String())
}
})
}
func TestGetDiffsForField(t *testing.T) {
t.Run("should not include fields that starts has prefix", func(t *testing.T) {
diff := DiffReport{
Diff{
Path: "Property",
},
Diff{
Path: "PropertyData",
},
}
result := diff.GetDiffsForField("Property")
require.Len(t, result, 1)
require.Len(t, result.Paths(), 1)
require.Equal(t, "Property", result[0].Path)
})
t.Run("should return all changes by parent path", func(t *testing.T) {
diff := DiffReport{
Diff{
Path: "Property.Data.Value",
},
Diff{
Path: "Property.Array[0].Value",
},
}
result := diff.GetDiffsForField("Property")
require.Len(t, result, 2)
require.Len(t, result.Paths(), 2)
})
t.Run("should return all elements of array", func(t *testing.T) {
diff := DiffReport{
Diff{
Path: "Property[0].Data.Test",
},
Diff{
Path: "Property",
},
Diff{
Path: "Property[1]",
},
}
result := diff.GetDiffsForField("Property")
require.Len(t, result, 3)
require.Len(t, result.Paths(), 3)
})
t.Run("should find nothing if parent path does not exist", func(t *testing.T) {
diff := DiffReport{
Diff{
Path: "Property[0].Data.Test",
},
Diff{
Path: "Property",
},
Diff{
Path: "Property[1]",
},
}
result := diff.GetDiffsForField("Proper")
require.Empty(t, result)
require.Empty(t, result.Paths())
})
}