mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-07-28 21:41:59 +08:00
296 lines
8.7 KiB
Go
296 lines
8.7 KiB
Go
package telemetrymetrics
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
|
|
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
|
|
"github.com/huandu/go-sqlbuilder"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestConditionFor(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
testCases := []struct {
|
|
name string
|
|
key telemetrytypes.TelemetryFieldKey
|
|
operator qbtypes.FilterOperator
|
|
value any
|
|
expectedSQL string
|
|
expectedArgs []any
|
|
expectedError error
|
|
}{
|
|
{
|
|
name: "Equal operator - string",
|
|
key: telemetrytypes.TelemetryFieldKey{
|
|
Name: "metric_name",
|
|
FieldContext: telemetrytypes.FieldContextMetric,
|
|
},
|
|
operator: qbtypes.FilterOperatorEqual,
|
|
value: "http.server.duration",
|
|
expectedSQL: "metric_name = ?",
|
|
expectedArgs: []any{"http.server.duration"},
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
name: "Not Equal operator - metric_name",
|
|
key: telemetrytypes.TelemetryFieldKey{
|
|
Name: "metric_name",
|
|
FieldContext: telemetrytypes.FieldContextMetric,
|
|
},
|
|
operator: qbtypes.FilterOperatorNotEqual,
|
|
value: "http.server.duration",
|
|
expectedSQL: "metric_name <> ?",
|
|
expectedArgs: []any{"http.server.duration"},
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
name: "Like operator - metric_name",
|
|
key: telemetrytypes.TelemetryFieldKey{
|
|
Name: "metric_name",
|
|
FieldContext: telemetrytypes.FieldContextMetric,
|
|
},
|
|
operator: qbtypes.FilterOperatorLike,
|
|
value: "%error%",
|
|
expectedSQL: "metric_name LIKE ?",
|
|
expectedArgs: []any{"%error%"},
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
name: "Not Like operator - metric_name",
|
|
key: telemetrytypes.TelemetryFieldKey{
|
|
Name: "metric_name",
|
|
FieldContext: telemetrytypes.FieldContextMetric,
|
|
},
|
|
operator: qbtypes.FilterOperatorNotLike,
|
|
value: "%error%",
|
|
expectedSQL: "metric_name NOT LIKE ?",
|
|
expectedArgs: []any{"%error%"},
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
name: "ILike operator - string label",
|
|
key: telemetrytypes.TelemetryFieldKey{
|
|
Name: "user.id",
|
|
FieldContext: telemetrytypes.FieldContextResource,
|
|
FieldDataType: telemetrytypes.FieldDataTypeString,
|
|
},
|
|
operator: qbtypes.FilterOperatorILike,
|
|
value: "%admin%",
|
|
expectedSQL: "LOWER(JSONExtractString(labels, 'user.id')) LIKE LOWER(?)",
|
|
expectedArgs: []any{"%admin%"},
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
name: "Not ILike operator - string label",
|
|
key: telemetrytypes.TelemetryFieldKey{
|
|
Name: "user.id",
|
|
FieldContext: telemetrytypes.FieldContextResource,
|
|
FieldDataType: telemetrytypes.FieldDataTypeString,
|
|
},
|
|
operator: qbtypes.FilterOperatorNotILike,
|
|
value: "%admin%",
|
|
expectedSQL: "LOWER(JSONExtractString(labels, 'user.id')) NOT LIKE LOWER(?)",
|
|
expectedArgs: []any{"%admin%"},
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
name: "Contains operator - string label",
|
|
key: telemetrytypes.TelemetryFieldKey{
|
|
Name: "user.id",
|
|
FieldContext: telemetrytypes.FieldContextResource,
|
|
FieldDataType: telemetrytypes.FieldDataTypeString,
|
|
},
|
|
operator: qbtypes.FilterOperatorContains,
|
|
value: "admin",
|
|
expectedSQL: "LOWER(JSONExtractString(labels, 'user.id')) LIKE LOWER(?)",
|
|
expectedArgs: []any{"%admin%"},
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
name: "In operator - metric_name",
|
|
key: telemetrytypes.TelemetryFieldKey{
|
|
Name: "metric_name",
|
|
FieldContext: telemetrytypes.FieldContextMetric,
|
|
},
|
|
operator: qbtypes.FilterOperatorIn,
|
|
value: []any{"http.server.duration", "http.server.request.duration", "http.server.response.duration"},
|
|
expectedSQL: "(metric_name = ? OR metric_name = ? OR metric_name = ?)",
|
|
expectedArgs: []any{"http.server.duration", "http.server.request.duration", "http.server.response.duration"},
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
name: "In operator - invalid value",
|
|
key: telemetrytypes.TelemetryFieldKey{
|
|
Name: "metric_name",
|
|
FieldContext: telemetrytypes.FieldContextMetric,
|
|
},
|
|
operator: qbtypes.FilterOperatorIn,
|
|
value: "error",
|
|
expectedSQL: "",
|
|
expectedError: qbtypes.ErrInValues,
|
|
},
|
|
{
|
|
name: "Not In operator - metric_name",
|
|
key: telemetrytypes.TelemetryFieldKey{
|
|
Name: "metric_name",
|
|
FieldContext: telemetrytypes.FieldContextMetric,
|
|
},
|
|
operator: qbtypes.FilterOperatorNotIn,
|
|
value: []any{"debug", "info", "trace"},
|
|
expectedSQL: "(metric_name <> ? AND metric_name <> ? AND metric_name <> ?)",
|
|
expectedArgs: []any{"debug", "info", "trace"},
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
name: "Exists operator - string field",
|
|
key: telemetrytypes.TelemetryFieldKey{
|
|
Name: "metric_name",
|
|
FieldContext: telemetrytypes.FieldContextMetric,
|
|
},
|
|
operator: qbtypes.FilterOperatorExists,
|
|
value: nil,
|
|
expectedSQL: "true",
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
name: "Not Exists operator - string field",
|
|
key: telemetrytypes.TelemetryFieldKey{
|
|
Name: "metric_name",
|
|
FieldContext: telemetrytypes.FieldContextMetric,
|
|
},
|
|
operator: qbtypes.FilterOperatorNotExists,
|
|
value: nil,
|
|
expectedSQL: "true",
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
name: "Exists operator - type",
|
|
key: telemetrytypes.TelemetryFieldKey{
|
|
Name: "type",
|
|
FieldContext: telemetrytypes.FieldContextMetric,
|
|
},
|
|
operator: qbtypes.FilterOperatorExists,
|
|
value: nil,
|
|
expectedSQL: "true",
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
name: "Exists operator - string label",
|
|
key: telemetrytypes.TelemetryFieldKey{
|
|
Name: "user.id",
|
|
FieldContext: telemetrytypes.FieldContextResource,
|
|
FieldDataType: telemetrytypes.FieldDataTypeString,
|
|
},
|
|
operator: qbtypes.FilterOperatorExists,
|
|
value: nil,
|
|
expectedSQL: "has(JSONExtractKeys(labels), 'user.id')",
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
name: "Not Exists operator - string label",
|
|
key: telemetrytypes.TelemetryFieldKey{
|
|
Name: "user.id",
|
|
FieldContext: telemetrytypes.FieldContextResource,
|
|
FieldDataType: telemetrytypes.FieldDataTypeString,
|
|
},
|
|
operator: qbtypes.FilterOperatorNotExists,
|
|
value: nil,
|
|
expectedSQL: "not has(JSONExtractKeys(labels), 'user.id')",
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
name: "Non-existent column",
|
|
key: telemetrytypes.TelemetryFieldKey{
|
|
Name: "nonexistent_field",
|
|
FieldContext: telemetrytypes.FieldContextMetric,
|
|
},
|
|
operator: qbtypes.FilterOperatorEqual,
|
|
value: "value",
|
|
expectedSQL: "",
|
|
expectedError: qbtypes.ErrColumnNotFound,
|
|
},
|
|
}
|
|
|
|
fm := NewFieldMapper()
|
|
conditionBuilder := NewConditionBuilder(fm)
|
|
|
|
for _, tc := range testCases {
|
|
sb := sqlbuilder.NewSelectBuilder()
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
cond, err := conditionBuilder.ConditionFor(ctx, &tc.key, tc.operator, tc.value, sb)
|
|
sb.Where(cond)
|
|
|
|
if tc.expectedError != nil {
|
|
assert.Equal(t, tc.expectedError, err)
|
|
} else {
|
|
require.NoError(t, err)
|
|
sql, args := sb.BuildWithFlavor(sqlbuilder.ClickHouse)
|
|
assert.Contains(t, sql, tc.expectedSQL)
|
|
assert.Equal(t, tc.expectedArgs, args)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestConditionForMultipleKeys(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
testCases := []struct {
|
|
name string
|
|
keys []telemetrytypes.TelemetryFieldKey
|
|
operator qbtypes.FilterOperator
|
|
value any
|
|
expectedSQL string
|
|
expectedArgs []any
|
|
expectedError error
|
|
}{
|
|
{
|
|
name: "Equal operator - string",
|
|
keys: []telemetrytypes.TelemetryFieldKey{
|
|
{
|
|
Name: "metric_name",
|
|
FieldContext: telemetrytypes.FieldContextMetric,
|
|
},
|
|
{
|
|
Name: "type",
|
|
FieldContext: telemetrytypes.FieldContextMetric,
|
|
},
|
|
},
|
|
operator: qbtypes.FilterOperatorEqual,
|
|
value: "error message",
|
|
expectedSQL: "metric_name = ? AND type = ?",
|
|
expectedArgs: []any{"error message", "error message"},
|
|
expectedError: nil,
|
|
},
|
|
}
|
|
|
|
fm := NewFieldMapper()
|
|
conditionBuilder := NewConditionBuilder(fm)
|
|
|
|
for _, tc := range testCases {
|
|
sb := sqlbuilder.NewSelectBuilder()
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var err error
|
|
for _, key := range tc.keys {
|
|
cond, err := conditionBuilder.ConditionFor(ctx, &key, tc.operator, tc.value, sb)
|
|
sb.Where(cond)
|
|
if err != nil {
|
|
t.Fatalf("Error getting condition for key %s: %v", key.Name, err)
|
|
}
|
|
}
|
|
|
|
if tc.expectedError != nil {
|
|
assert.Equal(t, tc.expectedError, err)
|
|
} else {
|
|
require.NoError(t, err)
|
|
sql, _ := sb.BuildWithFlavor(sqlbuilder.ClickHouse)
|
|
assert.Contains(t, sql, tc.expectedSQL)
|
|
}
|
|
})
|
|
}
|
|
}
|