613 lines
18 KiB
Go
613 lines
18 KiB
Go
|
package postprocess
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"encoding/json"
|
||
|
"reflect"
|
||
|
"testing"
|
||
|
|
||
|
"go.signoz.io/signoz/pkg/query-service/constants"
|
||
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||
|
)
|
||
|
|
||
|
func TestSortRows(t *testing.T) {
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
rows []*v3.TableRow
|
||
|
columns []*v3.TableColumn
|
||
|
builderQueries map[string]*v3.BuilderQuery
|
||
|
queryNames []string
|
||
|
expected []*v3.TableRow
|
||
|
}{
|
||
|
{
|
||
|
name: "Sort by single numeric query, ascending order",
|
||
|
rows: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service2", "A": 20.0}},
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": 10.0}},
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0}},
|
||
|
},
|
||
|
columns: []*v3.TableColumn{
|
||
|
{Name: "service_name"},
|
||
|
{Name: "A"},
|
||
|
},
|
||
|
builderQueries: map[string]*v3.BuilderQuery{
|
||
|
"A": {OrderBy: []v3.OrderBy{{ColumnName: constants.SigNozOrderByValue, Order: "asc"}}},
|
||
|
},
|
||
|
queryNames: []string{"A"},
|
||
|
expected: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": 10.0}},
|
||
|
{Data: map[string]interface{}{"service": "service2", "A": 20.0}},
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0}},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
name: "Sort by single numeric query, descending order",
|
||
|
rows: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service2", "A": 20.0}},
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": 10.0}},
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0}},
|
||
|
},
|
||
|
columns: []*v3.TableColumn{
|
||
|
{Name: "service_name"},
|
||
|
{Name: "A"},
|
||
|
},
|
||
|
builderQueries: map[string]*v3.BuilderQuery{
|
||
|
"A": {OrderBy: []v3.OrderBy{{ColumnName: constants.SigNozOrderByValue, Order: "desc"}}},
|
||
|
},
|
||
|
queryNames: []string{"A"},
|
||
|
expected: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0}},
|
||
|
{Data: map[string]interface{}{"service": "service2", "A": 20.0}},
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": 10.0}},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
name: "Sort by single string query, ascending order",
|
||
|
rows: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service2", "A": "b"}},
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": "c"}},
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": "a"}},
|
||
|
},
|
||
|
columns: []*v3.TableColumn{
|
||
|
{Name: "service_name"},
|
||
|
{Name: "A"},
|
||
|
},
|
||
|
builderQueries: map[string]*v3.BuilderQuery{
|
||
|
"A": {OrderBy: []v3.OrderBy{{ColumnName: "A", Order: "asc"}}},
|
||
|
},
|
||
|
queryNames: []string{"A"},
|
||
|
expected: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": "a"}},
|
||
|
{Data: map[string]interface{}{"service": "service2", "A": "b"}},
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": "c"}},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
name: "Sort with n/a values",
|
||
|
rows: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": 10.0}},
|
||
|
{Data: map[string]interface{}{"service": "service2", "B": 15.0}},
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0, "B": 25.0}},
|
||
|
{Data: map[string]interface{}{"service": "service4"}},
|
||
|
},
|
||
|
columns: []*v3.TableColumn{
|
||
|
{Name: "service_name"},
|
||
|
{Name: "A"},
|
||
|
{Name: "B"},
|
||
|
},
|
||
|
builderQueries: map[string]*v3.BuilderQuery{
|
||
|
"A": {OrderBy: []v3.OrderBy{{ColumnName: constants.SigNozOrderByValue, Order: "asc"}}},
|
||
|
"B": {OrderBy: []v3.OrderBy{{ColumnName: constants.SigNozOrderByValue, Order: "desc"}}},
|
||
|
},
|
||
|
queryNames: []string{"A", "B"},
|
||
|
expected: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": 10.0}},
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0, "B": 25.0}},
|
||
|
{Data: map[string]interface{}{"service": "service2", "B": 15.0}},
|
||
|
{Data: map[string]interface{}{"service": "service4"}},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
name: "Sort with SigNozOrderByValue",
|
||
|
rows: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": 20.0}},
|
||
|
{Data: map[string]interface{}{"service": "service2", "A": 10.0}},
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0}},
|
||
|
},
|
||
|
columns: []*v3.TableColumn{
|
||
|
{Name: "service_name"},
|
||
|
{Name: "A"},
|
||
|
},
|
||
|
builderQueries: map[string]*v3.BuilderQuery{
|
||
|
"A": {OrderBy: []v3.OrderBy{{ColumnName: constants.SigNozOrderByValue, Order: "desc"}}},
|
||
|
},
|
||
|
queryNames: []string{"A"},
|
||
|
expected: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0}},
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": 20.0}},
|
||
|
{Data: map[string]interface{}{"service": "service2", "A": 10.0}},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
name: "Sort with all n/a values",
|
||
|
rows: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": "n/a", "B": "n/a"}},
|
||
|
{Data: map[string]interface{}{"service": "service2", "A": "n/a", "B": "n/a"}},
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": "n/a", "B": "n/a"}},
|
||
|
},
|
||
|
columns: []*v3.TableColumn{
|
||
|
{Name: "service_name"},
|
||
|
{Name: "A"},
|
||
|
{Name: "B"},
|
||
|
},
|
||
|
builderQueries: map[string]*v3.BuilderQuery{
|
||
|
"A": {OrderBy: []v3.OrderBy{{ColumnName: "A", Order: "asc"}}},
|
||
|
"B": {OrderBy: []v3.OrderBy{{ColumnName: "B", Order: "desc"}}},
|
||
|
},
|
||
|
queryNames: []string{"A", "B"},
|
||
|
expected: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": "n/a", "B": "n/a"}},
|
||
|
{Data: map[string]interface{}{"service": "service2", "A": "n/a", "B": "n/a"}},
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": "n/a", "B": "n/a"}},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
name: "Sort with negative numbers",
|
||
|
rows: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": -10.0}},
|
||
|
{Data: map[string]interface{}{"service": "service2", "A": 20.0}},
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": -30.0}},
|
||
|
{Data: map[string]interface{}{"service": "service4", "A": 0.0}},
|
||
|
},
|
||
|
columns: []*v3.TableColumn{
|
||
|
{Name: "service_name"},
|
||
|
{Name: "A"},
|
||
|
},
|
||
|
builderQueries: map[string]*v3.BuilderQuery{
|
||
|
"A": {OrderBy: []v3.OrderBy{{ColumnName: "A", Order: "asc"}}},
|
||
|
},
|
||
|
queryNames: []string{"A"},
|
||
|
expected: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": -30.0}},
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": -10.0}},
|
||
|
{Data: map[string]interface{}{"service": "service4", "A": 0.0}},
|
||
|
{Data: map[string]interface{}{"service": "service2", "A": 20.0}},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
name: "Sort with mixed case strings",
|
||
|
rows: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": "Apple"}},
|
||
|
{Data: map[string]interface{}{"service": "service2", "A": "banana"}},
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": "Cherry"}},
|
||
|
{Data: map[string]interface{}{"service": "service4", "A": "date"}},
|
||
|
},
|
||
|
columns: []*v3.TableColumn{
|
||
|
{Name: "service_name"},
|
||
|
{Name: "A"},
|
||
|
},
|
||
|
builderQueries: map[string]*v3.BuilderQuery{
|
||
|
"A": {OrderBy: []v3.OrderBy{{ColumnName: "A", Order: "asc"}}},
|
||
|
},
|
||
|
queryNames: []string{"A"},
|
||
|
expected: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": "Apple"}},
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": "Cherry"}},
|
||
|
{Data: map[string]interface{}{"service": "service2", "A": "banana"}},
|
||
|
{Data: map[string]interface{}{"service": "service4", "A": "date"}},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
name: "Sort with empty strings",
|
||
|
rows: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": ""}},
|
||
|
{Data: map[string]interface{}{"service": "service2", "A": "b"}},
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": ""}},
|
||
|
{Data: map[string]interface{}{"service": "service4", "A": "a"}},
|
||
|
},
|
||
|
columns: []*v3.TableColumn{
|
||
|
{Name: "service_name"},
|
||
|
{Name: "A"},
|
||
|
},
|
||
|
builderQueries: map[string]*v3.BuilderQuery{
|
||
|
"A": {OrderBy: []v3.OrderBy{{ColumnName: "A", Order: "asc"}}},
|
||
|
},
|
||
|
queryNames: []string{"A"},
|
||
|
expected: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": ""}},
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": ""}},
|
||
|
{Data: map[string]interface{}{"service": "service4", "A": "a"}},
|
||
|
{Data: map[string]interface{}{"service": "service2", "A": "b"}},
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, tt := range tests {
|
||
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
sortRows(tt.rows, tt.builderQueries, tt.queryNames)
|
||
|
if !reflect.DeepEqual(tt.rows, tt.expected) {
|
||
|
exp, _ := json.Marshal(tt.expected)
|
||
|
got, _ := json.Marshal(tt.rows)
|
||
|
t.Errorf("sortRows() = %v, want %v", string(got), string(exp))
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSortRowsWithEmptyQueries(t *testing.T) {
|
||
|
rows := []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": 20.0}},
|
||
|
{Data: map[string]interface{}{"service": "service2", "A": 10.0}},
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0}},
|
||
|
}
|
||
|
builderQueries := map[string]*v3.BuilderQuery{}
|
||
|
queryNames := []string{}
|
||
|
|
||
|
sortRows(rows, builderQueries, queryNames)
|
||
|
|
||
|
// Expect the original order to be maintained
|
||
|
expected := []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": 20.0}},
|
||
|
{Data: map[string]interface{}{"service": "service2", "A": 10.0}},
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0}},
|
||
|
}
|
||
|
|
||
|
if !reflect.DeepEqual(rows, expected) {
|
||
|
t.Errorf("sortRows() with empty queries = %v, want %v", rows, expected)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSortRowsWithInvalidColumnName(t *testing.T) {
|
||
|
rows := []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": 20.0}},
|
||
|
{Data: map[string]interface{}{"service": "service2", "A": 10.0}},
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0}},
|
||
|
}
|
||
|
builderQueries := map[string]*v3.BuilderQuery{
|
||
|
"A": {OrderBy: []v3.OrderBy{{ColumnName: "InvalidColumn", Order: "asc"}}},
|
||
|
}
|
||
|
queryNames := []string{"A"}
|
||
|
|
||
|
sortRows(rows, builderQueries, queryNames)
|
||
|
|
||
|
// Expect the original order to be maintained
|
||
|
expected := []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": 20.0}},
|
||
|
{Data: map[string]interface{}{"service": "service2", "A": 10.0}},
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0}},
|
||
|
}
|
||
|
|
||
|
if !reflect.DeepEqual(rows, expected) {
|
||
|
t.Errorf("sortRows() with invalid column name = %v, want %v", rows, expected)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSortRowsStability(t *testing.T) {
|
||
|
rows := []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": 10.0, "B": "a"}},
|
||
|
{Data: map[string]interface{}{"service": "service2", "A": 10.0, "B": "b"}},
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": 10.0, "B": "c"}},
|
||
|
}
|
||
|
builderQueries := map[string]*v3.BuilderQuery{
|
||
|
"A": {OrderBy: []v3.OrderBy{{ColumnName: "A", Order: "asc"}}},
|
||
|
}
|
||
|
queryNames := []string{"A"}
|
||
|
|
||
|
sortRows(rows, builderQueries, queryNames)
|
||
|
|
||
|
// Expect the original order to be maintained for equal values
|
||
|
expected := []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "service1", "A": 10.0, "B": "a"}},
|
||
|
{Data: map[string]interface{}{"service": "service2", "A": 10.0, "B": "b"}},
|
||
|
{Data: map[string]interface{}{"service": "service3", "A": 10.0, "B": "c"}},
|
||
|
}
|
||
|
|
||
|
if !reflect.DeepEqual(rows, expected) {
|
||
|
t.Errorf("sortRows() stability test failed = %v, want %v", rows, expected)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestTransformToTableForClickHouseQueries(t *testing.T) {
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
input []*v3.Result
|
||
|
expected []*v3.Result
|
||
|
}{
|
||
|
{
|
||
|
name: "Empty input",
|
||
|
input: []*v3.Result{},
|
||
|
expected: []*v3.Result{},
|
||
|
},
|
||
|
{
|
||
|
name: "Single result with one series",
|
||
|
input: []*v3.Result{
|
||
|
{
|
||
|
QueryName: "A",
|
||
|
Series: []*v3.Series{
|
||
|
{
|
||
|
LabelsArray: []map[string]string{
|
||
|
{"service": "frontend"},
|
||
|
},
|
||
|
Points: []v3.Point{
|
||
|
{Value: 10.0},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
expected: []*v3.Result{
|
||
|
{
|
||
|
Table: &v3.Table{
|
||
|
Columns: []*v3.TableColumn{
|
||
|
{Name: "service"},
|
||
|
{Name: "A", QueryName: "A", IsValueColumn: true},
|
||
|
},
|
||
|
Rows: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "frontend", "A": 10.0}},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
name: "Multiple results with multiple series",
|
||
|
input: []*v3.Result{
|
||
|
{
|
||
|
QueryName: "A",
|
||
|
Series: []*v3.Series{
|
||
|
{
|
||
|
LabelsArray: []map[string]string{
|
||
|
{"service": "frontend"},
|
||
|
{"env": "prod"},
|
||
|
},
|
||
|
Points: []v3.Point{
|
||
|
{Value: 10.0},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
LabelsArray: []map[string]string{
|
||
|
{"service": "backend"},
|
||
|
{"env": "prod"},
|
||
|
},
|
||
|
Points: []v3.Point{
|
||
|
{Value: 20.0},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
QueryName: "B",
|
||
|
Series: []*v3.Series{
|
||
|
{
|
||
|
LabelsArray: []map[string]string{
|
||
|
{"service": "frontend"},
|
||
|
{"env": "prod"},
|
||
|
},
|
||
|
Points: []v3.Point{
|
||
|
{Value: 15.0},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
LabelsArray: []map[string]string{
|
||
|
{"service": "backend"},
|
||
|
{"env": "prod"},
|
||
|
},
|
||
|
Points: []v3.Point{
|
||
|
{Value: 25.0},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
expected: []*v3.Result{
|
||
|
{
|
||
|
Table: &v3.Table{
|
||
|
Columns: []*v3.TableColumn{
|
||
|
{Name: "service"},
|
||
|
{Name: "env"},
|
||
|
{Name: "A", QueryName: "A", IsValueColumn: true},
|
||
|
{Name: "B", QueryName: "B", IsValueColumn: true},
|
||
|
},
|
||
|
Rows: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "frontend", "env": "prod", "A": 10.0, "B": "n/a"}},
|
||
|
{Data: map[string]interface{}{"service": "backend", "env": "prod", "A": 20.0, "B": "n/a"}},
|
||
|
{Data: map[string]interface{}{"service": "frontend", "env": "prod", "A": "n/a", "B": 15.0}},
|
||
|
{Data: map[string]interface{}{"service": "backend", "env": "prod", "A": "n/a", "B": 25.0}},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
name: "Results with missing labels",
|
||
|
input: []*v3.Result{
|
||
|
{
|
||
|
QueryName: "A",
|
||
|
Series: []*v3.Series{
|
||
|
{
|
||
|
LabelsArray: []map[string]string{
|
||
|
{"service": "frontend"},
|
||
|
},
|
||
|
Points: []v3.Point{
|
||
|
{Value: 10.0},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
QueryName: "B",
|
||
|
Series: []*v3.Series{
|
||
|
{
|
||
|
LabelsArray: []map[string]string{
|
||
|
{"env": "prod"},
|
||
|
},
|
||
|
Points: []v3.Point{
|
||
|
{Value: 20.0},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
expected: []*v3.Result{
|
||
|
{
|
||
|
Table: &v3.Table{
|
||
|
Columns: []*v3.TableColumn{
|
||
|
{Name: "service"},
|
||
|
{Name: "env"},
|
||
|
{Name: "A", QueryName: "A", IsValueColumn: true},
|
||
|
{Name: "B", QueryName: "B", IsValueColumn: true},
|
||
|
},
|
||
|
Rows: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "frontend", "env": "n/a", "A": 10.0, "B": "n/a"}},
|
||
|
{Data: map[string]interface{}{"service": "n/a", "env": "prod", "A": "n/a", "B": 20.0}},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
name: "Results with empty series",
|
||
|
input: []*v3.Result{
|
||
|
{
|
||
|
QueryName: "A",
|
||
|
Series: []*v3.Series{
|
||
|
{
|
||
|
LabelsArray: []map[string]string{
|
||
|
{"service": "frontend"},
|
||
|
},
|
||
|
Points: []v3.Point{
|
||
|
{Value: 10.0},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
QueryName: "B",
|
||
|
Series: []*v3.Series{},
|
||
|
},
|
||
|
},
|
||
|
expected: []*v3.Result{
|
||
|
{
|
||
|
Table: &v3.Table{
|
||
|
Columns: []*v3.TableColumn{
|
||
|
{Name: "service"},
|
||
|
{Name: "A", QueryName: "A", IsValueColumn: true},
|
||
|
},
|
||
|
Rows: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "frontend", "A": 10.0}},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
name: "Results with empty points",
|
||
|
input: []*v3.Result{
|
||
|
{
|
||
|
QueryName: "A",
|
||
|
Series: []*v3.Series{
|
||
|
{
|
||
|
LabelsArray: []map[string]string{
|
||
|
{"service": "frontend"},
|
||
|
},
|
||
|
Points: []v3.Point{},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
QueryName: "B",
|
||
|
Series: []*v3.Series{
|
||
|
{
|
||
|
LabelsArray: []map[string]string{
|
||
|
{"service": "backend"},
|
||
|
},
|
||
|
Points: []v3.Point{
|
||
|
{Value: 20.0},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
expected: []*v3.Result{
|
||
|
{
|
||
|
Table: &v3.Table{
|
||
|
Columns: []*v3.TableColumn{
|
||
|
{Name: "service"},
|
||
|
{Name: "B", QueryName: "B", IsValueColumn: true},
|
||
|
},
|
||
|
Rows: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "frontend", "B": "n/a"}},
|
||
|
{Data: map[string]interface{}{"service": "backend", "B": 20.0}},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, tt := range tests {
|
||
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
result := TransformToTableForClickHouseQueries(tt.input)
|
||
|
exp, _ := json.Marshal(tt.expected)
|
||
|
got, _ := json.Marshal(result)
|
||
|
if !bytes.Equal(got, exp) {
|
||
|
t.Errorf("TransformToTableForClickHouseQueries() = %v, want %v", string(got), string(exp))
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestTransformToTableForClickHouseQueriesSorting(t *testing.T) {
|
||
|
input := []*v3.Result{
|
||
|
{
|
||
|
QueryName: "B",
|
||
|
Series: []*v3.Series{
|
||
|
{
|
||
|
LabelsArray: []map[string]string{
|
||
|
{"service": "frontend"},
|
||
|
},
|
||
|
Points: []v3.Point{
|
||
|
{Value: 10.0},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
QueryName: "A",
|
||
|
Series: []*v3.Series{
|
||
|
{
|
||
|
LabelsArray: []map[string]string{
|
||
|
{"service": "backend"},
|
||
|
},
|
||
|
Points: []v3.Point{
|
||
|
{Value: 20.0},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
expected := []*v3.Result{
|
||
|
{
|
||
|
Table: &v3.Table{
|
||
|
Columns: []*v3.TableColumn{
|
||
|
{Name: "service"},
|
||
|
{Name: "A", QueryName: "A", IsValueColumn: true},
|
||
|
{Name: "B", QueryName: "B", IsValueColumn: true},
|
||
|
},
|
||
|
Rows: []*v3.TableRow{
|
||
|
{Data: map[string]interface{}{"service": "backend", "A": 20.0, "B": "n/a"}},
|
||
|
{Data: map[string]interface{}{"service": "frontend", "A": "n/a", "B": 10.0}},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
result := TransformToTableForClickHouseQueries(input)
|
||
|
exp, _ := json.Marshal(expected)
|
||
|
got, _ := json.Marshal(result)
|
||
|
if !bytes.Equal(got, exp) {
|
||
|
t.Errorf("TransformToTableForClickHouseQueries() sorting test failed. Got %v, want %v", string(got), string(exp))
|
||
|
}
|
||
|
}
|