mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-07-07 13:21:47 +08:00
511 lines
12 KiB
Go
511 lines
12 KiB
Go
package resource
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
|
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
|
)
|
|
|
|
func Test_buildResourceFilter(t *testing.T) {
|
|
type args struct {
|
|
logsOp string
|
|
key string
|
|
op v3.FilterOperator
|
|
value interface{}
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want string
|
|
}{
|
|
{
|
|
name: "test exists",
|
|
args: args{
|
|
key: "service.name",
|
|
op: v3.FilterOperatorExists,
|
|
},
|
|
want: `simpleJSONHas(labels, 'service.name')`,
|
|
},
|
|
{
|
|
name: "test nexists",
|
|
args: args{
|
|
key: "service.name",
|
|
op: v3.FilterOperatorNotExists,
|
|
},
|
|
want: `not simpleJSONHas(labels, 'service.name')`,
|
|
},
|
|
{
|
|
name: "test regex",
|
|
args: args{
|
|
logsOp: "match(%s, %s)",
|
|
key: "service.name",
|
|
op: v3.FilterOperatorRegex,
|
|
value: ".*",
|
|
},
|
|
want: `match(simpleJSONExtractString(labels, 'service.name'), '.*')`,
|
|
},
|
|
{
|
|
name: "test contains",
|
|
args: args{
|
|
logsOp: "LIKE",
|
|
key: "service.name",
|
|
op: v3.FilterOperatorContains,
|
|
value: "Application%_",
|
|
},
|
|
want: `simpleJSONExtractString(lower(labels), 'service.name') LIKE '%application\%\_%'`,
|
|
},
|
|
{
|
|
name: "test eq",
|
|
args: args{
|
|
logsOp: "=",
|
|
key: "service.name",
|
|
op: v3.FilterOperatorEqual,
|
|
value: "Application%",
|
|
},
|
|
want: `simpleJSONExtractString(labels, 'service.name') = 'Application%'`,
|
|
},
|
|
{
|
|
name: "test value with quotes",
|
|
args: args{
|
|
logsOp: "=",
|
|
key: "service.name",
|
|
op: v3.FilterOperatorEqual,
|
|
value: "Application's",
|
|
},
|
|
want: `simpleJSONExtractString(labels, 'service.name') = 'Application\'s'`,
|
|
},
|
|
{
|
|
name: "test like",
|
|
args: args{
|
|
logsOp: "LIKE",
|
|
key: "service.name",
|
|
op: v3.FilterOperatorLike,
|
|
value: "Application%_",
|
|
},
|
|
want: `simpleJSONExtractString(lower(labels), 'service.name') LIKE 'application%_'`,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := buildResourceFilter(tt.args.logsOp, tt.args.key, tt.args.op, tt.args.value); got != tt.want {
|
|
t.Errorf("buildResourceFilter() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_buildIndexFilterForInOperator(t *testing.T) {
|
|
type args struct {
|
|
key string
|
|
op v3.FilterOperator
|
|
value interface{}
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want string
|
|
}{
|
|
{
|
|
name: "test in array",
|
|
args: args{
|
|
key: "service.name",
|
|
op: v3.FilterOperatorIn,
|
|
value: []interface{}{"Application", "Test"},
|
|
},
|
|
want: `(labels like '%"service.name":"Application"%' OR labels like '%"service.name":"Test"%')`,
|
|
},
|
|
{
|
|
name: "test nin array",
|
|
args: args{
|
|
key: "service.name",
|
|
op: v3.FilterOperatorNotIn,
|
|
value: []interface{}{"Application", "Test"},
|
|
},
|
|
want: `(labels not like '%"service.name":"Application"%' AND labels not like '%"service.name":"Test"%')`,
|
|
},
|
|
{
|
|
name: "test in string",
|
|
args: args{
|
|
key: "service.name",
|
|
op: v3.FilterOperatorIn,
|
|
value: "application%",
|
|
},
|
|
want: `(labels like '%"service.name":"application\%"%')`,
|
|
},
|
|
{
|
|
name: "test nin string",
|
|
args: args{
|
|
key: "service.name",
|
|
op: v3.FilterOperatorNotIn,
|
|
value: `application'"_s`,
|
|
},
|
|
want: `(labels not like '%"service.name":"application\'\\\\"\_s"%')`,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := buildIndexFilterForInOperator(tt.args.key, tt.args.op, tt.args.value); got != tt.want {
|
|
t.Errorf("buildIndexFilterForInOperator() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_buildResourceIndexFilter(t *testing.T) {
|
|
type args struct {
|
|
key string
|
|
op v3.FilterOperator
|
|
value interface{}
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want string
|
|
}{
|
|
{
|
|
name: "test contains",
|
|
args: args{
|
|
key: "service.name",
|
|
op: v3.FilterOperatorContains,
|
|
value: "application",
|
|
},
|
|
want: `lower(labels) like '%service.name%application%'`,
|
|
},
|
|
{
|
|
name: "test not contains",
|
|
args: args{
|
|
key: "service.name",
|
|
op: v3.FilterOperatorNotContains,
|
|
value: "application",
|
|
},
|
|
want: `lower(labels) not like '%service.name%application%'`,
|
|
},
|
|
{
|
|
name: "test contains with % and _",
|
|
args: args{
|
|
key: "service.name",
|
|
op: v3.FilterOperatorNotContains,
|
|
value: "application%_test",
|
|
},
|
|
want: `lower(labels) not like '%service.name%application\%\_test%'`,
|
|
},
|
|
{
|
|
name: "test like with % and _",
|
|
args: args{
|
|
key: "service.name",
|
|
op: v3.FilterOperatorLike,
|
|
value: "Application%_test",
|
|
},
|
|
want: `lower(labels) like '%service.name%application%_test%'`,
|
|
},
|
|
{
|
|
name: "test like with % and _",
|
|
args: args{
|
|
key: "service.name",
|
|
op: v3.FilterOperatorLike,
|
|
value: "application%_test",
|
|
},
|
|
want: `lower(labels) like '%service.name%application%_test%'`,
|
|
},
|
|
{
|
|
name: "test not regex",
|
|
args: args{
|
|
key: "service.name",
|
|
op: v3.FilterOperatorNotRegex,
|
|
value: ".*",
|
|
},
|
|
want: ``,
|
|
},
|
|
{
|
|
name: "test in",
|
|
args: args{
|
|
key: "service.name",
|
|
op: v3.FilterOperatorNotIn,
|
|
value: []interface{}{"Application", "Test"},
|
|
},
|
|
want: `(labels not like '%"service.name":"Application"%' AND labels not like '%"service.name":"Test"%')`,
|
|
},
|
|
{
|
|
name: "test eq",
|
|
args: args{
|
|
key: "service.name",
|
|
op: v3.FilterOperatorEqual,
|
|
value: `Application"`,
|
|
},
|
|
want: `labels like '%service.name%Application\\\\"%'`,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := buildResourceIndexFilter(tt.args.key, tt.args.op, tt.args.value); got != tt.want {
|
|
t.Errorf("buildResourceIndexFilter() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_buildResourceFiltersFromFilterItems(t *testing.T) {
|
|
type args struct {
|
|
fs *v3.FilterSet
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want []string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "ignore attribute",
|
|
args: args{
|
|
fs: &v3.FilterSet{
|
|
Items: []v3.FilterItem{
|
|
{
|
|
Key: v3.AttributeKey{
|
|
Key: "service.name",
|
|
DataType: v3.AttributeKeyDataTypeString,
|
|
Type: v3.AttributeKeyTypeTag,
|
|
},
|
|
Operator: v3.FilterOperatorEqual,
|
|
Value: "test",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: nil,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "build filter",
|
|
args: args{
|
|
fs: &v3.FilterSet{
|
|
Items: []v3.FilterItem{
|
|
{
|
|
Key: v3.AttributeKey{
|
|
Key: "service.name",
|
|
DataType: v3.AttributeKeyDataTypeString,
|
|
Type: v3.AttributeKeyTypeResource,
|
|
},
|
|
Operator: v3.FilterOperatorEqual,
|
|
Value: "test",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: []string{
|
|
"simpleJSONExtractString(labels, 'service.name') = 'test'",
|
|
"labels like '%service.name%test%'",
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "build filter with multiple items",
|
|
args: args{
|
|
fs: &v3.FilterSet{
|
|
Items: []v3.FilterItem{
|
|
{
|
|
Key: v3.AttributeKey{
|
|
Key: "service.name",
|
|
DataType: v3.AttributeKeyDataTypeString,
|
|
Type: v3.AttributeKeyTypeResource,
|
|
},
|
|
Operator: v3.FilterOperatorEqual,
|
|
Value: "test",
|
|
},
|
|
{
|
|
Key: v3.AttributeKey{
|
|
Key: "namespace",
|
|
DataType: v3.AttributeKeyDataTypeString,
|
|
Type: v3.AttributeKeyTypeResource,
|
|
},
|
|
Operator: v3.FilterOperatorContains,
|
|
Value: `test1"`,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: []string{
|
|
"simpleJSONExtractString(labels, 'service.name') = 'test'",
|
|
"labels like '%service.name%test%'",
|
|
`simpleJSONExtractString(lower(labels), 'namespace') LIKE '%test1"%'`,
|
|
`lower(labels) like '%namespace%test1\\\\"%'`,
|
|
},
|
|
wantErr: false,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := buildResourceFiltersFromFilterItems(tt.args.fs)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("buildResourceFiltersFromFilterItems() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("buildResourceFiltersFromFilterItems() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_buildResourceFiltersFromGroupBy(t *testing.T) {
|
|
type args struct {
|
|
groupBy []v3.AttributeKey
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want []string
|
|
}{
|
|
{
|
|
name: "build filter",
|
|
args: args{
|
|
groupBy: []v3.AttributeKey{
|
|
{
|
|
Key: "service.name",
|
|
DataType: v3.AttributeKeyDataTypeString,
|
|
Type: v3.AttributeKeyTypeResource,
|
|
},
|
|
},
|
|
},
|
|
want: []string{
|
|
"(simpleJSONHas(labels, 'service.name') AND labels like '%service.name%')",
|
|
},
|
|
},
|
|
{
|
|
name: "build filter multiple group by",
|
|
args: args{
|
|
groupBy: []v3.AttributeKey{
|
|
{
|
|
Key: "service.name",
|
|
DataType: v3.AttributeKeyDataTypeString,
|
|
Type: v3.AttributeKeyTypeResource,
|
|
},
|
|
{
|
|
Key: "namespace",
|
|
DataType: v3.AttributeKeyDataTypeString,
|
|
Type: v3.AttributeKeyTypeResource,
|
|
},
|
|
},
|
|
},
|
|
want: []string{
|
|
"(simpleJSONHas(labels, 'service.name') AND labels like '%service.name%')",
|
|
"(simpleJSONHas(labels, 'namespace') AND labels like '%namespace%')",
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := buildResourceFiltersFromGroupBy(tt.args.groupBy); !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("buildResourceFiltersFromGroupBy() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_buildResourceFiltersFromAggregateAttribute(t *testing.T) {
|
|
type args struct {
|
|
aggregateAttribute v3.AttributeKey
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want string
|
|
}{
|
|
{
|
|
name: "build filter",
|
|
args: args{
|
|
aggregateAttribute: v3.AttributeKey{
|
|
Key: "service.name",
|
|
DataType: v3.AttributeKeyDataTypeString,
|
|
Type: v3.AttributeKeyTypeResource,
|
|
},
|
|
},
|
|
want: "(simpleJSONHas(labels, 'service.name') AND labels like '%service.name%')",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := buildResourceFiltersFromAggregateAttribute(tt.args.aggregateAttribute); got != tt.want {
|
|
t.Errorf("buildResourceFiltersFromAggregateAttribute() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_buildResourceSubQuery(t *testing.T) {
|
|
type args struct {
|
|
bucketStart int64
|
|
bucketEnd int64
|
|
fs *v3.FilterSet
|
|
groupBy []v3.AttributeKey
|
|
aggregateAttribute v3.AttributeKey
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "build sub query",
|
|
args: args{
|
|
bucketStart: 1680064560,
|
|
bucketEnd: 1680066458,
|
|
fs: &v3.FilterSet{
|
|
Items: []v3.FilterItem{
|
|
{
|
|
Key: v3.AttributeKey{
|
|
Key: "service.name",
|
|
DataType: v3.AttributeKeyDataTypeString,
|
|
Type: v3.AttributeKeyTypeResource,
|
|
},
|
|
Operator: v3.FilterOperatorEqual,
|
|
Value: "test",
|
|
},
|
|
{
|
|
Key: v3.AttributeKey{
|
|
Key: "namespace",
|
|
DataType: v3.AttributeKeyDataTypeString,
|
|
Type: v3.AttributeKeyTypeResource,
|
|
},
|
|
Operator: v3.FilterOperatorContains,
|
|
Value: "test1",
|
|
},
|
|
},
|
|
},
|
|
groupBy: []v3.AttributeKey{
|
|
{
|
|
Key: "host.name",
|
|
DataType: v3.AttributeKeyDataTypeString,
|
|
Type: v3.AttributeKeyTypeResource,
|
|
},
|
|
},
|
|
aggregateAttribute: v3.AttributeKey{
|
|
Key: "cluster.name",
|
|
DataType: v3.AttributeKeyDataTypeString,
|
|
Type: v3.AttributeKeyTypeResource,
|
|
},
|
|
},
|
|
want: "(SELECT fingerprint FROM signoz_logs.distributed_logs_v2_resource WHERE " +
|
|
"(seen_at_ts_bucket_start >= 1680064560) AND (seen_at_ts_bucket_start <= 1680066458) AND " +
|
|
"simpleJSONExtractString(labels, 'service.name') = 'test' AND labels like '%service.name%test%' " +
|
|
"AND simpleJSONExtractString(lower(labels), 'namespace') LIKE '%test1%' AND lower(labels) like '%namespace%test1%' " +
|
|
"AND (simpleJSONHas(labels, 'cluster.name') AND labels like '%cluster.name%') AND " +
|
|
"( (simpleJSONHas(labels, 'host.name') AND labels like '%host.name%') ))",
|
|
wantErr: false,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := BuildResourceSubQuery("signoz_logs", "distributed_logs_v2_resource", tt.args.bucketStart, tt.args.bucketEnd, tt.args.fs, tt.args.groupBy, tt.args.aggregateAttribute, false)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("buildResourceSubQuery() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("buildResourceSubQuery() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|