mirror of
https://github.com/SigNoz/signoz.git
synced 2025-12-17 15:36:48 +00:00
261 lines
8.4 KiB
Go
261 lines
8.4 KiB
Go
|
|
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)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|