Skip to content

Commit 2928546

Browse files
committed
feat(backend): fix ut
1 parent be7a732 commit 2928546

File tree

1 file changed

+219
-0
lines changed

1 file changed

+219
-0
lines changed
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
// Copyright (c) 2025 coze-dev Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package ck
5+
6+
import (
7+
"context"
8+
"testing"
9+
10+
"github.com/DATA-DOG/go-sqlmock"
11+
"github.com/stretchr/testify/assert"
12+
"gorm.io/driver/clickhouse"
13+
"gorm.io/gorm"
14+
15+
"github.com/coze-dev/coze-loop/backend/modules/observability/domain/trace/entity/loop_span"
16+
"github.com/coze-dev/coze-loop/backend/modules/observability/infra/repo/ck/gorm_gen/model"
17+
"github.com/coze-dev/coze-loop/backend/pkg/lang/ptr"
18+
)
19+
20+
func TestBuildSql(t *testing.T) {
21+
sqlDB, _, err := sqlmock.New()
22+
if err != nil {
23+
t.Fatal("Failed to create mock")
24+
}
25+
defer func() {
26+
_ = sqlDB.Close()
27+
}()
28+
// 用mock DB替换GORM的DB
29+
db, err := gorm.Open(clickhouse.New(clickhouse.Config{
30+
Conn: sqlDB,
31+
SkipInitializeWithVersion: true,
32+
}), &gorm.Config{})
33+
if err != nil {
34+
t.Fatal(err)
35+
}
36+
type testCase struct {
37+
filter *loop_span.FilterFields
38+
expectedSql string
39+
}
40+
testCases := []testCase{
41+
{
42+
filter: &loop_span.FilterFields{
43+
FilterFields: []*loop_span.FilterField{
44+
{
45+
FieldName: "a",
46+
FieldType: loop_span.FieldTypeString,
47+
Values: []string{"1"},
48+
QueryType: ptr.Of(loop_span.QueryTypeEnumIn),
49+
SubFilter: &loop_span.FilterFields{
50+
FilterFields: []*loop_span.FilterField{
51+
{
52+
FieldName: "aa",
53+
FieldType: loop_span.FieldTypeString,
54+
Values: []string{"aaa"},
55+
QueryType: ptr.Of(loop_span.QueryTypeEnumIn),
56+
QueryAndOr: ptr.Of(loop_span.QueryAndOrEnumOr),
57+
SubFilter: &loop_span.FilterFields{
58+
FilterFields: []*loop_span.FilterField{
59+
{
60+
FieldName: "a",
61+
FieldType: loop_span.FieldTypeString,
62+
Values: []string{"b"},
63+
QueryType: ptr.Of(loop_span.QueryTypeEnumEq),
64+
},
65+
},
66+
},
67+
},
68+
},
69+
},
70+
},
71+
{
72+
FieldName: "b",
73+
FieldType: loop_span.FieldTypeString,
74+
Values: []string{"b"},
75+
QueryType: ptr.Of(loop_span.QueryTypeEnumNotIn),
76+
QueryAndOr: ptr.Of(loop_span.QueryAndOrEnumOr),
77+
SubFilter: &loop_span.FilterFields{
78+
FilterFields: []*loop_span.FilterField{
79+
{
80+
FieldName: "c",
81+
FieldType: loop_span.FieldTypeString,
82+
Values: []string{"c"},
83+
QueryType: ptr.Of(loop_span.QueryTypeEnumNotIn),
84+
},
85+
{
86+
FieldName: "c",
87+
FieldType: loop_span.FieldTypeString,
88+
Values: []string{"d"},
89+
QueryType: ptr.Of(loop_span.QueryTypeEnumNotIn),
90+
},
91+
{
92+
FieldName: "c",
93+
FieldType: loop_span.FieldTypeString,
94+
Values: []string{"e"},
95+
QueryType: ptr.Of(loop_span.QueryTypeEnumNotIn),
96+
},
97+
},
98+
},
99+
},
100+
},
101+
},
102+
expectedSql: "SELECT * FROM `observability_spans` WHERE ((tags_string['a'] IN ('1') AND (tags_string['aa'] IN ('aaa') OR tags_string['a'] = 'b')) AND (tags_string['b'] NOT IN ('b') OR (tags_string['c'] NOT IN ('c') AND tags_string['c'] NOT IN ('d') AND tags_string['c'] NOT IN ('e')))) AND start_time >= 1 AND start_time <= 2 LIMIT 100",
103+
},
104+
{
105+
filter: &loop_span.FilterFields{
106+
FilterFields: []*loop_span.FilterField{
107+
{
108+
FieldName: "custom_tag_string",
109+
FieldType: loop_span.FieldTypeString,
110+
Values: []string{},
111+
QueryType: ptr.Of(loop_span.QueryTypeEnumNotExist),
112+
},
113+
{
114+
FieldName: "custom_tag_bool",
115+
FieldType: loop_span.FieldTypeBool,
116+
Values: []string{},
117+
QueryType: ptr.Of(loop_span.QueryTypeEnumNotExist),
118+
},
119+
{
120+
FieldName: "custom_tag_double",
121+
FieldType: loop_span.FieldTypeDouble,
122+
Values: []string{},
123+
QueryType: ptr.Of(loop_span.QueryTypeEnumNotExist),
124+
},
125+
{
126+
FieldName: "custom_tag_long",
127+
FieldType: loop_span.FieldTypeLong,
128+
Values: []string{},
129+
QueryType: ptr.Of(loop_span.QueryTypeEnumNotExist),
130+
},
131+
},
132+
},
133+
expectedSql: "SELECT * FROM `observability_spans` WHERE ((tags_string['custom_tag_string'] IS NULL OR tags_string['custom_tag_string'] = '') AND (tags_bool['custom_tag_bool'] IS NULL OR tags_bool['custom_tag_bool'] = 0) AND (tags_float['custom_tag_double'] IS NULL OR tags_float['custom_tag_double'] = 0) AND (tags_long['custom_tag_long'] IS NULL OR tags_long['custom_tag_long'] = 0)) AND start_time >= 1 AND start_time <= 2 LIMIT 100",
134+
},
135+
{
136+
filter: &loop_span.FilterFields{
137+
FilterFields: []*loop_span.FilterField{
138+
{
139+
FieldName: "custom_tag_long",
140+
FieldType: loop_span.FieldTypeLong,
141+
Values: []string{"123", "-123"},
142+
QueryType: ptr.Of(loop_span.QueryTypeEnumIn),
143+
},
144+
},
145+
},
146+
expectedSql: "SELECT * FROM `observability_spans` WHERE tags_long['custom_tag_long'] IN (123,-123) AND start_time >= 1 AND start_time <= 2 LIMIT 100",
147+
},
148+
{
149+
filter: &loop_span.FilterFields{
150+
FilterFields: []*loop_span.FilterField{
151+
{
152+
FieldName: "custom_tag_float64",
153+
FieldType: loop_span.FieldTypeDouble,
154+
Values: []string{"123.999"},
155+
QueryType: ptr.Of(loop_span.QueryTypeEnumEq),
156+
},
157+
},
158+
},
159+
expectedSql: "SELECT * FROM `observability_spans` WHERE tags_float['custom_tag_float64'] = 123.999 AND start_time >= 1 AND start_time <= 2 LIMIT 100",
160+
},
161+
{
162+
filter: &loop_span.FilterFields{
163+
FilterFields: []*loop_span.FilterField{
164+
{
165+
FieldName: loop_span.SpanFieldDuration,
166+
FieldType: loop_span.FieldTypeLong,
167+
Values: []string{"121"},
168+
QueryType: ptr.Of(loop_span.QueryTypeEnumGte),
169+
},
170+
},
171+
},
172+
expectedSql: "SELECT * FROM `observability_spans` WHERE `duration` >= 121 AND start_time >= 1 AND start_time <= 2 LIMIT 100",
173+
},
174+
{
175+
filter: &loop_span.FilterFields{
176+
FilterFields: []*loop_span.FilterField{
177+
{
178+
FieldName: "custom_tag_bool",
179+
FieldType: loop_span.FieldTypeBool,
180+
Values: []string{"true"},
181+
QueryType: ptr.Of(loop_span.QueryTypeEnumEq),
182+
},
183+
},
184+
},
185+
expectedSql: "SELECT * FROM `observability_spans` WHERE tags_bool['custom_tag_bool'] = 1 AND start_time >= 1 AND start_time <= 2 LIMIT 100",
186+
},
187+
{
188+
filter: &loop_span.FilterFields{
189+
FilterFields: []*loop_span.FilterField{
190+
{
191+
FieldName: loop_span.SpanFieldInput,
192+
FieldType: loop_span.FieldTypeString,
193+
Values: []string{"123"},
194+
QueryType: ptr.Of(loop_span.QueryTypeEnumMatch),
195+
},
196+
},
197+
},
198+
expectedSql: "SELECT * FROM `observability_spans` WHERE `input` like '%123%' AND start_time >= 1 AND start_time <= 2 LIMIT 100",
199+
},
200+
}
201+
for _, tc := range testCases {
202+
qDb, err := new(SpansCkDaoImpl).buildSingleSql(context.Background(), &buildSqlParam{
203+
spanTable: "observability_spans",
204+
queryParam: &QueryParam{
205+
StartTime: 1,
206+
EndTime: 2,
207+
Filters: tc.filter,
208+
Limit: 100,
209+
},
210+
db: db,
211+
})
212+
assert.Nil(t, err)
213+
sql := qDb.ToSQL(func(tx *gorm.DB) *gorm.DB {
214+
return tx.Find([]*model.ObservabilitySpan{})
215+
})
216+
t.Log(sql)
217+
assert.Equal(t, tc.expectedSql, sql)
218+
}
219+
}

0 commit comments

Comments
 (0)