signoz/pkg/querier/postprocess_table_test.go
2025-06-12 16:50:10 +05:30

290 lines
8.0 KiB
Go

package querier
import (
"testing"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestFormatScalarResultsAsTableMergesCorrectly(t *testing.T) {
q := &querier{}
// Create results that simulate the problematic case
results := map[string]*qbtypes.Result{
"A": {
Value: &qbtypes.ScalarData{
Columns: []*qbtypes.ColumnDescriptor{
{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "service.name"},
QueryName: "A",
Type: qbtypes.ColumnTypeGroup,
},
{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "__result_0"},
QueryName: "A",
AggregationIndex: 0,
Type: qbtypes.ColumnTypeAggregation,
},
{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "__result_1"},
QueryName: "A",
AggregationIndex: 1,
Type: qbtypes.ColumnTypeAggregation,
},
},
Data: [][]any{
{"currencyservice", 3380.0, 1.0},
{"mongodb", 5713.0, 1.0},
{"cartservice", 3322.0, 1.0},
},
},
},
"B": {
Value: &qbtypes.ScalarData{
Columns: []*qbtypes.ColumnDescriptor{
{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "service.name"},
QueryName: "B",
Type: qbtypes.ColumnTypeGroup,
},
{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "__result_0"},
QueryName: "B",
AggregationIndex: 0,
Type: qbtypes.ColumnTypeAggregation,
},
},
Data: [][]any{
{"currencyservice", 1.0},
{"mongodb", 1.0},
{"cartservice", 1.0},
{"kafka", 1.0}, // Service only in B
},
},
},
}
req := &qbtypes.QueryRangeRequest{
CompositeQuery: qbtypes.CompositeQuery{
Queries: []qbtypes.QueryEnvelope{
{
Type: qbtypes.QueryTypeBuilder,
Spec: qbtypes.QueryBuilderQuery[qbtypes.MetricAggregation]{
Name: "A",
},
},
{
Type: qbtypes.QueryTypeBuilder,
Spec: qbtypes.QueryBuilderQuery[qbtypes.MetricAggregation]{
Name: "B",
},
},
},
},
}
// Format as table
result := q.formatScalarResultsAsTable(results, req)
// Get the table
table, ok := result["table"].(*qbtypes.ScalarData)
require.True(t, ok)
// Should have 5 columns: 1 group + 2 from A + 1 from B
assert.Len(t, table.Columns, 4)
// Check column names and query associations
assert.Equal(t, "service.name", table.Columns[0].Name)
assert.Equal(t, qbtypes.ColumnTypeGroup, table.Columns[0].Type)
assert.Equal(t, "__result_0", table.Columns[1].Name)
assert.Equal(t, "A", table.Columns[1].QueryName)
assert.Equal(t, qbtypes.ColumnTypeAggregation, table.Columns[1].Type)
assert.Equal(t, "__result_1", table.Columns[2].Name)
assert.Equal(t, "A", table.Columns[2].QueryName)
assert.Equal(t, qbtypes.ColumnTypeAggregation, table.Columns[2].Type)
assert.Equal(t, "__result_0", table.Columns[3].Name)
assert.Equal(t, "B", table.Columns[3].QueryName)
assert.Equal(t, qbtypes.ColumnTypeAggregation, table.Columns[3].Type)
// Should have 4 rows (one for each unique service)
assert.Len(t, table.Data, 4)
// Create a map to check row values by service name
rowMap := make(map[string][]any)
for _, row := range table.Data {
serviceName := row[0].(string)
rowMap[serviceName] = row
}
// Check currencyservice row
currencyRow := rowMap["currencyservice"]
assert.Equal(t, "currencyservice", currencyRow[0])
assert.Equal(t, 3380.0, currencyRow[1]) // A result 0
assert.Equal(t, 1.0, currencyRow[2]) // A result 1
assert.Equal(t, 1.0, currencyRow[3]) // B result 0
// Check mongodb row
mongoRow := rowMap["mongodb"]
assert.Equal(t, "mongodb", mongoRow[0])
assert.Equal(t, 5713.0, mongoRow[1]) // A result 0
assert.Equal(t, 1.0, mongoRow[2]) // A result 1
assert.Equal(t, 1.0, mongoRow[3]) // B result 0
// Check cartservice row
cartRow := rowMap["cartservice"]
assert.Equal(t, "cartservice", cartRow[0])
assert.Equal(t, 3322.0, cartRow[1]) // A result 0
assert.Equal(t, 1.0, cartRow[2]) // A result 1
assert.Equal(t, 1.0, cartRow[3]) // B result 0
// Check kafka row (only in B)
kafkaRow := rowMap["kafka"]
assert.Equal(t, "kafka", kafkaRow[0])
assert.Equal(t, "n/a", kafkaRow[1]) // A result 0
assert.Equal(t, "n/a", kafkaRow[2]) // A result 1
assert.Equal(t, 1.0, kafkaRow[3]) // B result 0
}
func TestFormatScalarResultsAsTableWithTimeSeriesData(t *testing.T) {
q := &querier{}
// Create time series results that need to be converted to scalar
results := map[string]*qbtypes.Result{
"A": {
Value: &qbtypes.TimeSeriesData{
QueryName: "A",
Aggregations: []*qbtypes.AggregationBucket{
{
Index: 0,
Alias: "count",
Series: []*qbtypes.TimeSeries{
{
Labels: []*qbtypes.Label{
{
Key: telemetrytypes.TelemetryFieldKey{Name: "service.name"},
Value: "frontend",
},
},
Values: []*qbtypes.TimeSeriesValue{
{Timestamp: 1000, Value: 100},
{Timestamp: 2000, Value: 200},
},
},
{
Labels: []*qbtypes.Label{
{
Key: telemetrytypes.TelemetryFieldKey{Name: "service.name"},
Value: "backend",
},
},
Values: []*qbtypes.TimeSeriesValue{
{Timestamp: 1000, Value: 300},
{Timestamp: 2000, Value: 400},
},
},
},
},
},
},
},
"B": {
Value: &qbtypes.TimeSeriesData{
QueryName: "B",
Aggregations: []*qbtypes.AggregationBucket{
{
Index: 0,
Alias: "sum",
Series: []*qbtypes.TimeSeries{
{
Labels: []*qbtypes.Label{
{
Key: telemetrytypes.TelemetryFieldKey{Name: "service.name"},
Value: "frontend",
},
},
Values: []*qbtypes.TimeSeriesValue{
{Timestamp: 1000, Value: 10},
{Timestamp: 2000, Value: 20},
},
},
{
Labels: []*qbtypes.Label{
{
Key: telemetrytypes.TelemetryFieldKey{Name: "service.name"},
Value: "backend",
},
},
Values: []*qbtypes.TimeSeriesValue{
{Timestamp: 1000, Value: 30},
{Timestamp: 2000, Value: 40},
},
},
},
},
},
},
},
}
req := &qbtypes.QueryRangeRequest{
CompositeQuery: qbtypes.CompositeQuery{
Queries: []qbtypes.QueryEnvelope{
{
Type: qbtypes.QueryTypeBuilder,
Spec: qbtypes.QueryBuilderQuery[qbtypes.MetricAggregation]{
Name: "A",
},
},
{
Type: qbtypes.QueryTypeBuilder,
Spec: qbtypes.QueryBuilderQuery[qbtypes.MetricAggregation]{
Name: "B",
},
},
},
},
}
// Format as table
result := q.formatScalarResultsAsTable(results, req)
// Get the table
table, ok := result["table"].(*qbtypes.ScalarData)
require.True(t, ok)
// Should have 3 columns: 1 group + 1 from A + 1 from B
assert.Len(t, table.Columns, 3)
// Check column names
assert.Equal(t, "service.name", table.Columns[0].Name)
assert.Equal(t, "count", table.Columns[1].Name) // Should use alias
assert.Equal(t, "sum", table.Columns[2].Name) // Should use alias
// Should have 2 rows (frontend and backend)
assert.Len(t, table.Data, 2)
// Create a map to check row values by service name
rowMap := make(map[string][]any)
for _, row := range table.Data {
serviceName := row[0].(string)
rowMap[serviceName] = row
}
// Check frontend row (should have last values)
frontendRow := rowMap["frontend"]
assert.Equal(t, "frontend", frontendRow[0])
assert.Equal(t, 200.0, frontendRow[1]) // Last value from A
assert.Equal(t, 20.0, frontendRow[2]) // Last value from B
// Check backend row
backendRow := rowMap["backend"]
assert.Equal(t, "backend", backendRow[0])
assert.Equal(t, 400.0, backendRow[1]) // Last value from A
assert.Equal(t, 40.0, backendRow[2]) // Last value from B
}