Skip to content

Commit 2dba77c

Browse files
committed
feat(backend): fix ut
1 parent 8360487 commit 2dba77c

File tree

9 files changed

+549
-493
lines changed

9 files changed

+549
-493
lines changed

backend/modules/observability/domain/metric/service/metric/metric_definitions_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"go.uber.org/mock/gomock"
1616

1717
"github.com/coze-dev/coze-loop/backend/modules/observability/domain/metric/entity"
18+
consts "github.com/coze-dev/coze-loop/backend/modules/observability/domain/metric/service/metric/const"
1819
generalmetrics "github.com/coze-dev/coze-loop/backend/modules/observability/domain/metric/service/metric/general"
1920
modelmetrics "github.com/coze-dev/coze-loop/backend/modules/observability/domain/metric/service/metric/model"
2021
servicemetrics "github.com/coze-dev/coze-loop/backend/modules/observability/domain/metric/service/metric/service"
@@ -204,6 +205,7 @@ func renderExpressions(t *testing.T, defs []entity.IMetricDefinition, gran entit
204205
_ = def.Type()
205206
_ = def.GroupBy()
206207
_ = def.Source()
208+
_ = def.OExpression()
207209
_, _ = def.Where(context.Background(), f, nil)
208210
res[def.Name()] = renderExpression(t, def, gran)
209211
}
@@ -239,6 +241,77 @@ func expectedBaseExpression(name string, gran entity.MetricGranularity) (string,
239241
return "", false
240242
}
241243

244+
// 额外覆盖:校验各 Wrapper 与复合指标、常量指标的行为
245+
func TestWrapperProperties(t *testing.T) {
246+
ctrl := gomock.NewController(t)
247+
defer ctrl.Finish()
248+
249+
defs := []entity.IMetricDefinition{
250+
modelmetrics.NewModelDurationMetric(),
251+
servicemetrics.NewServiceDurationMetric(),
252+
}
253+
granularities := []entity.MetricGranularity{entity.MetricGranularity1Min, entity.MetricGranularity1Hour}
254+
255+
for _, def := range defs {
256+
adapter, ok := def.(entity.IMetricAdapter)
257+
require.True(t, ok)
258+
wrappers := adapter.Wrappers()
259+
require.NotEmpty(t, wrappers)
260+
for _, w := range wrappers {
261+
wrapped := w.Wrap(def)
262+
// 名称后缀断言
263+
name := wrapped.Name()
264+
require.True(t, strings.HasPrefix(name, def.Name()))
265+
require.True(t, strings.HasSuffix(name, "_avg") || strings.HasSuffix(name, "_min") || strings.HasSuffix(name, "_max") || strings.HasSuffix(name, "_pct50") || strings.HasSuffix(name, "_pct90") || strings.HasSuffix(name, "_pct99") || strings.HasSuffix(name, "_sum") || strings.HasSuffix(name, "_by_time"))
266+
// 类型与表达式不为空
267+
require.NotEmpty(t, wrapped.Type())
268+
for _, gran := range granularities {
269+
expr := wrapped.Expression(gran)
270+
require.NotNil(t, expr)
271+
require.NotEmpty(t, expr.Expression)
272+
}
273+
// OExpression 非空(用于离线计算)
274+
require.NotNil(t, wrapped.OExpression())
275+
// Where/GroupBy 可调用
276+
f := spanfiltermocks.NewMockFilter(ctrl)
277+
f.EXPECT().BuildLLMSpanFilter(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
278+
f.EXPECT().BuildRootSpanFilter(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
279+
_, _ = wrapped.Where(context.Background(), f, nil)
280+
_ = wrapped.GroupBy()
281+
}
282+
}
283+
}
284+
285+
func TestCompoundMetricsDefinition(t *testing.T) {
286+
compoundDefs := []entity.IMetricDefinition{
287+
generalmetrics.NewGeneralModelLatencyMetric(),
288+
generalmetrics.NewGeneralToolLatencyMetric(),
289+
}
290+
for _, def := range compoundDefs {
291+
compound, ok := def.(entity.IMetricCompound)
292+
require.True(t, ok)
293+
// 复合指标的运算符与子指标集合
294+
require.Equal(t, entity.MetricOperatorDivide, compound.Operator())
295+
subs := compound.GetMetrics()
296+
require.Len(t, subs, 2)
297+
// 子指标的表达式可渲染
298+
for _, sub := range subs {
299+
expr := sub.Expression(entity.MetricGranularity1Min)
300+
require.NotNil(t, expr)
301+
}
302+
}
303+
}
304+
305+
func TestConstMinuteMetric(t *testing.T) {
306+
def := consts.NewConstMinuteMetric()
307+
// 常量指标基本属性
308+
require.Equal(t, entity.MetricTypeSummary, def.Type())
309+
// 1min 粒度下表达式应为 "1"
310+
expr := def.Expression(entity.MetricGranularity1Min)
311+
require.NotNil(t, expr)
312+
require.Equal(t, "1", expr.Expression)
313+
}
314+
242315
var baseExpressionGenerators = map[string]func(entity.MetricGranularity) string{
243316
entity.MetricNameGeneralTotalCount: countExpr,
244317
entity.MetricNameGeneralToolTotalCount: countExpr,

backend/modules/observability/domain/metric/service/offline_metric_test.go

Lines changed: 21 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/coze-dev/coze-loop/backend/modules/observability/domain/metric/entity"
1313
"github.com/coze-dev/coze-loop/backend/modules/observability/domain/metric/repo"
1414
repomocks "github.com/coze-dev/coze-loop/backend/modules/observability/domain/metric/repo/mocks"
15+
consts "github.com/coze-dev/coze-loop/backend/modules/observability/domain/metric/service/metric/const"
1516
"github.com/coze-dev/coze-loop/backend/modules/observability/domain/trace/entity/loop_span"
1617
"github.com/coze-dev/coze-loop/backend/modules/observability/domain/trace/service/trace/span_filter"
1718
"github.com/stretchr/testify/assert"
@@ -93,7 +94,7 @@ func TestMetricsService_buildDrillDownFields(t *testing.T) {
9394
FieldType: loop_span.FieldTypeString,
9495
},
9596
"group_obj": {
96-
FieldName: "group_field",
97+
FieldName: "group_field",
9798
FieldType: loop_span.FieldTypeString,
9899
},
99100
"metric_obj": {
@@ -128,12 +129,12 @@ func TestMetricsService_buildDrillDownFields(t *testing.T) {
128129
result := svc.buildDrillDownFields(platformCfg, groupCfg, definition)
129130

130131
assert.Len(t, result, 4) // platform + group + metric + space_id
131-
132+
132133
fieldNames := make([]string, len(result))
133134
for i, field := range result {
134135
fieldNames[i] = field.FieldName
135136
}
136-
137+
137138
assert.Contains(t, fieldNames, "platform_field")
138139
assert.Contains(t, fieldNames, "group_field")
139140
assert.Contains(t, fieldNames, "metric_field")
@@ -183,7 +184,7 @@ func TestMetricsService_buildDrillDownFields(t *testing.T) {
183184
fieldCount++
184185
}
185186
}
186-
187+
187188
assert.Equal(t, 1, fieldCount) // 同一个字段只应该出现一次
188189
assert.Len(t, result, 2) // common_field + space_id
189190
})
@@ -230,11 +231,11 @@ func TestMetricsService_extractMetrics(t *testing.T) {
230231
events := svc.extractMetrics("test_metric", metric)
231232

232233
assert.Len(t, events, 2)
233-
234+
234235
// 验证第一个事件(有分组)
235236
assert.Equal(t, "100", events[0].MetricValue)
236237
assert.Equal(t, "group1", events[0].ObjectKeys["group_field"])
237-
238+
238239
// 验证第二个事件(默认分组)
239240
assert.Equal(t, "200", events[1].MetricValue)
240241
assert.Empty(t, events[1].ObjectKeys)
@@ -291,14 +292,14 @@ func TestMetricsService_extractMetrics(t *testing.T) {
291292
Pie: map[string]string{
292293
`{"category_alias":"A"}`: "100",
293294
`{"category_alias":"B"}`: "200",
294-
"all": "300",
295+
"all": "300",
295296
},
296297
}
297298

298299
events := svc.extractMetrics("test_metric", metric)
299300

300301
assert.Len(t, events, 3)
301-
302+
302303
// 验证事件值
303304
values := make([]string, len(events))
304305
for i, event := range events {
@@ -335,7 +336,7 @@ func TestMetricsService_queryOfflineMetrics(t *testing.T) {
335336
defer ctrl.Finish()
336337

337338
repoMock := repomocks.NewMockIOfflineMetricRepo(ctrl)
338-
339+
339340
// 模拟多次查询调用
340341
repoMock.EXPECT().
341342
GetMetrics(gomock.Any(), gomock.Any()).
@@ -353,7 +354,7 @@ func TestMetricsService_queryOfflineMetrics(t *testing.T) {
353354
}
354355

355356
metricDefB := &testMetricDefinition{
356-
name: "metric_b",
357+
name: "metric_b",
357358
metricType: entity.MetricTypeSummary,
358359
}
359360

@@ -411,7 +412,7 @@ func TestMetricsService_queryOfflineMetrics(t *testing.T) {
411412
defer ctrl.Finish()
412413

413414
repoMock := repomocks.NewMockIOfflineMetricRepo(ctrl)
414-
415+
415416
repoMock.EXPECT().
416417
GetMetrics(gomock.Any(), gomock.Any()).
417418
Return(nil, errors.New("database error")).
@@ -523,7 +524,7 @@ func TestMetricsService_buildOfflineMetricQuery(t *testing.T) {
523524

524525
assert.NoError(t, err)
525526
assert.NotNil(t, builder)
526-
527+
527528
// 验证过滤条件中使用了自定义的metric name
528529
filters := builder.mRepoReq.Filters
529530
assert.NotNil(t, filters)
@@ -603,12 +604,7 @@ func TestMetricsService_buildTraverseMetrics(t *testing.T) {
603604
ctrl := gomock.NewController(t)
604605
defer ctrl.Finish()
605606

606-
constDef := &testConstMetricDefinition{
607-
testMetricDefinition: &testMetricDefinition{
608-
name: "const_metric",
609-
metricType: entity.MetricTypeSummary,
610-
},
611-
}
607+
constDef := consts.NewConstMinuteMetric()
612608

613609
pMetrics := &entity.PlatformMetrics{
614610
MetricGroups: map[string]*entity.MetricGroup{
@@ -626,19 +622,18 @@ func TestMetricsService_buildTraverseMetrics(t *testing.T) {
626622

627623
svc := &MetricsService{
628624
metricDefMap: map[string]entity.IMetricDefinition{
629-
"const_metric": constDef,
625+
constDef.Name(): constDef,
630626
},
631627
pMetrics: pMetrics,
632628
}
633629

634630
metrics, err := svc.buildTraverseMetrics(context.Background(), &TraverseMetricsReq{
635631
PlatformTypes: []loop_span.PlatformType{"test_platform"},
636-
MetricsNames: []string{"const_metric"},
632+
MetricsNames: []string{},
637633
})
638634

639635
assert.NoError(t, err)
640-
assert.Len(t, metrics, 1) // 常量指标在buildTraverseMetrics中不会被跳过,只有在traverseMetric中才会被跳过
641-
// 注意:常量指标是在traverseMetric阶段被跳过的,不是在buildTraverseMetrics阶段
636+
assert.Len(t, metrics, 0)
642637
})
643638

644639
t.Run("metric not found in metricDefMap", func(t *testing.T) {
@@ -704,7 +699,7 @@ func TestMetricsService_buildTraverseMetrics(t *testing.T) {
704699
defer ctrl.Finish()
705700

706701
pMetrics := &entity.PlatformMetrics{
707-
MetricGroups: map[string]*entity.MetricGroup{},
702+
MetricGroups: map[string]*entity.MetricGroup{},
708703
DrillDownObjects: map[string]*loop_span.FilterField{},
709704
PlatformMetricDefs: map[loop_span.PlatformType]*entity.PlatformMetricDef{
710705
loop_span.PlatformType("test_platform"): {
@@ -768,26 +763,19 @@ func TestMetricsService_buildTraverseMetrics(t *testing.T) {
768763
WorkspaceID: 1,
769764
StartDate: "2025-11-17",
770765
}
771-
766+
772767
// 模拟TraverseMetrics方法中的处理逻辑
773768
if len(req.PlatformTypes) == 0 {
774769
req.PlatformTypes = []loop_span.PlatformType{"platform1", "platform2"}
775770
}
776-
771+
777772
metrics, err := svc.buildTraverseMetrics(context.Background(), req)
778773

779774
assert.NoError(t, err)
780775
assert.Len(t, metrics, 2) // 两个平台类型
781776
})
782777
}
783778

784-
// 辅助测试结构体
785-
type testConstMetricDefinition struct {
786-
*testMetricDefinition
787-
}
788-
789-
func (d *testConstMetricDefinition) constFunc() {}
790-
791779
// 自定义测试指标定义,支持自定义OExpression
792780
type customTestMetricDefinition struct {
793781
name string
@@ -829,4 +817,4 @@ func (d *customTestMetricDefinition) OExpression() *entity.OExpression {
829817
AggrType: entity.MetricOfflineAggrTypeSum,
830818
MetricName: d.name,
831819
}
832-
}
820+
}

0 commit comments

Comments
 (0)