signoz/pkg/contextlinks/alert_link_visitor_test.go

261 lines
8.4 KiB
Go
Raw Normal View History

package contextlinks
import (
"testing"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
"github.com/stretchr/testify/assert"
)
func TestPrepareFiltersV5(t *testing.T) {
tests := []struct {
name string
labels map[string]string
whereClause string
groupByItems []qbtypes.GroupByKey
expected string
description string
}{
{
name: "empty_inputs",
labels: map[string]string{},
whereClause: "",
groupByItems: []qbtypes.GroupByKey{},
expected: "",
description: "Should return empty string for empty inputs",
},
{
name: "no_label_replacement",
labels: map[string]string{},
whereClause: "service.name = 'serviceB'",
groupByItems: []qbtypes.GroupByKey{
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "service.name"}},
},
expected: "service.name='serviceB'",
description: "No change",
},
{
name: "in_clause_replacement",
labels: map[string]string{
"severity_text": "WARN",
},
whereClause: "severity_text IN ('WARN', 'ERROR')",
groupByItems: []qbtypes.GroupByKey{
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "severity_text"}},
},
expected: "severity_text='WARN'",
description: "Should replace IN clause with actual value when key is in group by",
},
{
name: "missing_label_addition", // case 2
labels: map[string]string{
"service.name": "serviceA",
},
whereClause: "status_code > 400",
groupByItems: []qbtypes.GroupByKey{
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "service.name"}},
},
expected: "(status_code>400) AND service.name='serviceA'",
description: "Should add missing labels from labels map",
},
{
name: "multiple_missing_labels",
labels: map[string]string{
"service.name": "serviceA",
"region": "us-east-1",
},
whereClause: "status_code > 400",
groupByItems: []qbtypes.GroupByKey{
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "service.name"}},
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "region"}},
},
expected: "(status_code>400) AND region='us-east-1' AND service.name='serviceA'",
description: "Should add all missing labels",
},
{
name: "complex_where_clause",
labels: map[string]string{
"service.name": "serviceA",
},
whereClause: "(status_code > 400 OR status_code < 200) AND method = 'GET'",
groupByItems: []qbtypes.GroupByKey{
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "service.name"}},
},
expected: "((status_code>400 OR status_code<200) AND method='GET') AND service.name='serviceA'",
description: "Should preserve complex boolean logic and add missing labels",
},
{
name: "label_not_in_group_by",
labels: map[string]string{
"service.name": "serviceA",
},
whereClause: "service.name = 'serviceB'",
groupByItems: []qbtypes.GroupByKey{
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "region"}}, // service.name not in group by
},
expected: "service.name='serviceB'",
description: "Should not replace label if not in group by items",
},
{
name: "special_characters_in_values",
labels: map[string]string{
"message": "Error: Connection failed",
"path": "/api/v1/users",
},
whereClause: "",
groupByItems: []qbtypes.GroupByKey{
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "message"}},
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "path"}},
},
expected: "message='Error: Connection failed' AND path='/api/v1/users'",
description: "Should quote values with special characters",
},
{
name: "numeric_and_boolean_values",
labels: map[string]string{
"count": "42",
"isEnabled": "true",
},
whereClause: "",
groupByItems: []qbtypes.GroupByKey{
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "count"}},
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "isEnabled"}},
},
expected: "count=42 AND isEnabled=true",
description: "Should not quote numeric and boolean values",
},
{
name: "like_operator",
labels: map[string]string{
"path": "/api/users",
},
whereClause: "path LIKE '/api%'",
groupByItems: []qbtypes.GroupByKey{
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "path"}},
},
expected: "path='/api/users'",
description: "Should replace LIKE comparisons when key is in group by",
},
{
name: "not_operators",
labels: map[string]string{
"status": "active",
},
whereClause: "status NOT IN ('deleted', 'archived')",
groupByItems: []qbtypes.GroupByKey{
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "status"}},
},
expected: "status='active'",
description: "Should replace NOT IN clause when key is in group by",
},
{
name: "between_operator",
labels: map[string]string{
"response_time": "250",
},
whereClause: "response_time BETWEEN 100 AND 500",
groupByItems: []qbtypes.GroupByKey{
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "response_time"}},
},
expected: "response_time=250",
description: "Should replace BETWEEN clause when key is in group by",
},
{
name: "function_calls",
labels: map[string]string{
"service.name": "serviceA",
},
whereClause: "has(tags, 'production')",
groupByItems: []qbtypes.GroupByKey{
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "service.name"}},
},
expected: "(has(tags, 'production')) AND service.name='serviceA'",
description: "Should preserve function calls and add missing labels",
},
{
name: "already_quoted_values",
labels: map[string]string{
"message": "\"Error message\"",
"tag": "'production'",
},
whereClause: "",
groupByItems: []qbtypes.GroupByKey{
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "message"}},
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "tag"}},
},
expected: "message='\"Error message\"' AND tag='\\'production\\''",
description: "Should not double-quote already quoted values",
},
{
name: "mixed_replacement_and_addition",
labels: map[string]string{
"service.name": "serviceA",
"severity_text": "ERROR",
"region": "us-west-2",
},
whereClause: "severity_text IN ('WARN', 'ERROR') AND status_code > 400",
groupByItems: []qbtypes.GroupByKey{
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "service.name"}},
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "severity_text"}},
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "region"}},
},
expected: "(severity_text='ERROR' AND status_code>400) AND region='us-west-2' AND service.name='serviceA'",
description: "Should both replace existing labels and add missing ones",
},
{
name: "implicit_and_handling",
labels: map[string]string{
"env": "production",
},
whereClause: "status_code=200 method='GET'", // implicit AND
groupByItems: []qbtypes.GroupByKey{
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "env"}},
},
expected: "(status_code=200 AND method='GET') AND env='production'",
description: "Should handle implicit AND between expressions",
},
{
name: "exists_operator",
labels: map[string]string{
"service.name": "serviceA",
},
whereClause: "error_details EXISTS",
groupByItems: []qbtypes.GroupByKey{
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "service.name"}},
},
expected: "(error_details EXISTS) AND service.name='serviceA'",
description: "Should preserve EXISTS operator",
},
{
name: "empty_where_clause_with_labels",
labels: map[string]string{
"service.name": "serviceA",
"region": "us-east-1",
},
whereClause: "",
groupByItems: []qbtypes.GroupByKey{
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "service.name"}},
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "region"}},
},
expected: "region='us-east-1' AND service.name='serviceA'",
description: "Should create where clause from labels when original is empty",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := PrepareFilterExpression(tt.labels, tt.whereClause, tt.groupByItems)
assert.Equal(t, tt.expected, result, tt.description)
})
}
}