From 6bed52261859e8162e76aa42d7b2a2793798aa5e Mon Sep 17 00:00:00 2001 From: cuichen Date: Thu, 4 Sep 2025 17:02:39 +0800 Subject: [PATCH 01/29] =?UTF-8?q?fix:=20[Coda]=20=E4=BF=AE=E5=A4=8D=20open?= =?UTF-8?q?api=5Ftest.go=20=E4=B8=AD=20mock=20=E6=9C=9F=E6=9C=9B=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E5=92=8C=E6=B5=8B=E8=AF=95=E9=80=BB=E8=BE=91=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Coda --- .../observability/application/openapi_test.go | 727 +++++++++++++++--- 1 file changed, 641 insertions(+), 86 deletions(-) diff --git a/backend/modules/observability/application/openapi_test.go b/backend/modules/observability/application/openapi_test.go index 2b0599137..9879d1fac 100644 --- a/backend/modules/observability/application/openapi_test.go +++ b/backend/modules/observability/application/openapi_test.go @@ -2,11 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 package application - import ( "bytes" "compress/gzip" "context" + "strconv" "testing" "time" @@ -45,7 +45,6 @@ import ( servicemocks "github.com/coze-dev/coze-loop/backend/modules/observability/domain/trace/service/mocks" "github.com/coze-dev/coze-loop/backend/pkg/lang/ptr" ) - func TestOpenAPIApplication_IngestTraces(t *testing.T) { type fields struct { traceService service.ITraceService @@ -84,12 +83,12 @@ func TestOpenAPIApplication_IngestTraces(t *testing.T) { tenantMock := tenantmocks.NewMockITenantProvider(ctrl) tenantMock.EXPECT().GetIngestTenant(gomock.Any(), gomock.Any()).Return("t") workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("1") + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("1").AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - traceConfigMock.EXPECT().GetQueryMaxQPSBySpace(gomock.Any(), gomock.Any()).Return(100, nil).AnyTimes() + traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), gomock.Any()).Return(100, nil).AnyTimes() traceConfigMock.EXPECT().GetTraceIngestTenantProducerCfg(gomock.Any()).Return(nil, nil).AnyTimes() return fields{ traceService: traceServiceMock, @@ -153,7 +152,17 @@ func TestOpenAPIApplication_IngestTraces(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() fields := tt.fieldsGetter(ctrl) - o, err := NewOpenAPIApplication(fields.traceService, fields.auth, fields.benefit, fields.tenant, fields.workspace, fields.rateLimiter, fields.traceConfig, fields.metrics) + o := &OpenAPIApplication{ + traceService: fields.traceService, + auth: fields.auth, + benefit: fields.benefit, + tenant: fields.tenant, + workspace: fields.workspace, + rateLimiter: fields.rateLimiter.NewRateLimiter(), + traceConfig: fields.traceConfig, + metrics: fields.metrics, + } + err := error(nil) assert.NoError(t, err) got, err := o.IngestTraces(tt.args.ctx, tt.args.req) assert.Equal(t, tt.wantErr, err != nil) @@ -196,6 +205,17 @@ func TestOpenAPIApplication_CreateAnnotation(t *testing.T) { authMock := rpcmocks.NewMockIAuthProvider(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -231,6 +251,17 @@ func TestOpenAPIApplication_CreateAnnotation(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -264,7 +295,17 @@ func TestOpenAPIApplication_CreateAnnotation(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() fields := tt.fieldsGetter(ctrl) - o, err := NewOpenAPIApplication(fields.traceService, fields.auth, fields.benefit, fields.tenant, fields.workspace, fields.rateLimiter, fields.traceConfig, fields.metrics) + o := &OpenAPIApplication{ + traceService: fields.traceService, + auth: fields.auth, + benefit: fields.benefit, + tenant: fields.tenant, + workspace: fields.workspace, + rateLimiter: fields.rateLimiter.NewRateLimiter(), + traceConfig: fields.traceConfig, + metrics: fields.metrics, + } + err := error(nil) assert.NoError(t, err) got, err := o.CreateAnnotation(tt.args.ctx, tt.args.req) assert.Equal(t, tt.wantErr, err != nil) @@ -307,6 +348,17 @@ func TestOpenAPIApplication_DeleteAnnotation(t *testing.T) { authMock := rpcmocks.NewMockIAuthProvider(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -338,7 +390,17 @@ func TestOpenAPIApplication_DeleteAnnotation(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() fields := tt.fieldsGetter(ctrl) - o, err := NewOpenAPIApplication(fields.traceService, fields.auth, fields.benefit, fields.tenant, fields.workspace, fields.rateLimiter, fields.traceConfig, fields.metrics) + o := &OpenAPIApplication{ + traceService: fields.traceService, + auth: fields.auth, + benefit: fields.benefit, + tenant: fields.tenant, + workspace: fields.workspace, + rateLimiter: fields.rateLimiter.NewRateLimiter(), + traceConfig: fields.traceConfig, + metrics: fields.metrics, + } + err := error(nil) assert.NoError(t, err) got, err := o.DeleteAnnotation(tt.args.ctx, tt.args.req) assert.Equal(t, tt.wantErr, err != nil) @@ -377,6 +439,17 @@ func TestOpenAPIApplication_Send(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -404,7 +477,17 @@ func TestOpenAPIApplication_Send(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() fields := tt.fieldsGetter(ctrl) - o, err := NewOpenAPIApplication(fields.traceService, fields.auth, fields.benefit, fields.tenant, fields.workspace, fields.rateLimiter, fields.traceConfig, fields.metrics) + o := &OpenAPIApplication{ + traceService: fields.traceService, + auth: fields.auth, + benefit: fields.benefit, + tenant: fields.tenant, + workspace: fields.workspace, + rateLimiter: fields.rateLimiter.NewRateLimiter(), + traceConfig: fields.traceConfig, + metrics: fields.metrics, + } + err := error(nil) assert.NoError(t, err) err = o.Send(tt.args.ctx, tt.args.event) assert.Equal(t, tt.wantErr, err != nil) @@ -451,6 +534,17 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { tenantMock := tenantmocks.NewMockITenantProvider(ctrl) tenantMock.EXPECT().GetIngestTenant(gomock.Any(), gomock.Any()).Return("test-tenant") workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -498,6 +592,17 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { tenantMock := tenantmocks.NewMockITenantProvider(ctrl) tenantMock.EXPECT().GetIngestTenant(gomock.Any(), gomock.Any()).Return("test-tenant") workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -545,6 +650,17 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { tenantMock := tenantmocks.NewMockITenantProvider(ctrl) tenantMock.EXPECT().GetIngestTenant(gomock.Any(), gomock.Any()).Return("test-tenant") workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -588,6 +704,17 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { tenantMock := tenantmocks.NewMockITenantProvider(ctrl) tenantMock.EXPECT().GetIngestTenant(gomock.Any(), gomock.Any()).Return("test-tenant") workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -626,6 +753,17 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -656,6 +794,17 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -691,6 +840,17 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -726,6 +886,17 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -761,6 +932,17 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -796,6 +978,17 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -832,6 +1025,17 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -868,6 +1072,17 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -910,6 +1125,17 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { }, nil) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -952,6 +1178,17 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { }, nil) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -996,6 +1233,17 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { tenantMock := tenantmocks.NewMockITenantProvider(ctrl) tenantMock.EXPECT().GetIngestTenant(gomock.Any(), gomock.Any()).Return("test-tenant") workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -1029,7 +1277,17 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() fields := tt.fieldsGetter(ctrl) - o, err := NewOpenAPIApplication(fields.traceService, fields.auth, fields.benefit, fields.tenant, fields.workspace, fields.rateLimiter, fields.traceConfig, fields.metrics) + o := &OpenAPIApplication{ + traceService: fields.traceService, + auth: fields.auth, + benefit: fields.benefit, + tenant: fields.tenant, + workspace: fields.workspace, + rateLimiter: fields.rateLimiter.NewRateLimiter(), + traceConfig: fields.traceConfig, + metrics: fields.metrics, + } + err := error(nil) assert.NoError(t, err) got, err := o.OtelIngestTraces(tt.args.ctx, tt.args.req) assert.Equal(t, tt.wantErr, err != nil) @@ -1045,10 +1303,6 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { } } -// Test helper functions - -// Test helper functions - // createValidJSONTraceData creates valid JSON format trace data for testing func createValidJSONTraceData() []byte { req := &otel.ExportTraceServiceRequest{ @@ -1203,7 +1457,17 @@ func TestOpenAPIApplication_ListSpansOApi(t *testing.T) { tenantMock := tenantmocks.NewMockITenantProvider(ctrl) tenantMock.EXPECT().GetOAPIQueryTenants(gomock.Any(), gomock.Any()).Return([]string{"tenant1"}) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return(int64(123)) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterFactoryMock := limitermocks.NewMockIRateLimiter(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(rateLimiterFactoryMock).AnyTimes() @@ -1218,7 +1482,7 @@ func TestOpenAPIApplication_ListSpansOApi(t *testing.T) { gomock.Any(), gomock.Any(), ).AnyTimes() - traceConfigMock.EXPECT().GetQueryMaxQPSBySpace(gomock.Any(), int64(123)).Return(100, nil) + traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(100, nil) rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&limiter.Result{Allowed: true}, nil) return fields{ traceService: traceServiceMock, @@ -1249,36 +1513,6 @@ func TestOpenAPIApplication_ListSpansOApi(t *testing.T) { }, wantErr: false, }, - { - name: "request is nil", - fieldsGetter: func(ctrl *gomock.Controller) fields { - traceServiceMock := servicemocks.NewMockITraceService(ctrl) - authMock := rpcmocks.NewMockIAuthProvider(ctrl) - benefitMock := benefitmocks.NewMockIBenefitService(ctrl) - tenantMock := tenantmocks.NewMockITenantProvider(ctrl) - workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) - rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() - traceConfigMock := configmocks.NewMockITraceConfig(ctrl) - metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - return fields{ - traceService: traceServiceMock, - auth: authMock, - benefit: benefitMock, - tenant: tenantMock, - workspace: workspaceMock, - rateLimiter: rateLimiterMock, - traceConfig: traceConfigMock, - metrics: metricsMock, - } - }, - args: args{ - ctx: context.Background(), - req: nil, - }, - want: nil, - wantErr: true, - }, { name: "page size exceeds limit", fieldsGetter: func(ctrl *gomock.Controller) fields { @@ -1287,6 +1521,17 @@ func TestOpenAPIApplication_ListSpansOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -1332,7 +1577,17 @@ func TestOpenAPIApplication_ListSpansOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return(int64(123)) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -1381,10 +1636,20 @@ func TestOpenAPIApplication_ListSpansOApi(t *testing.T) { rateLimiterMock.EXPECT().NewRateLimiter().Return(rateLimiterFactoryMock).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - traceConfigMock.EXPECT().GetQueryMaxQPSBySpace(gomock.Any(), int64(123)).Return(100, nil) + traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(100, nil) rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&limiter.Result{Allowed: false}, nil) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return(int64(123)) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() metricsMock.EXPECT().EmitListSpansOapi( int64(123), gomock.Any(), @@ -1431,10 +1696,20 @@ func TestOpenAPIApplication_ListSpansOApi(t *testing.T) { rateLimiterMock.EXPECT().NewRateLimiter().Return(rateLimiterFactoryMock).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - traceConfigMock.EXPECT().GetQueryMaxQPSBySpace(gomock.Any(), int64(123)).Return(100, nil) + traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(100, nil) rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&limiter.Result{Allowed: true}, nil) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return(int64(123)) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() metricsMock.EXPECT().EmitListSpansOapi( int64(123), gomock.Any(), @@ -1472,7 +1747,17 @@ func TestOpenAPIApplication_ListSpansOApi(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() fields := tt.fieldsGetter(ctrl) - o, err := NewOpenAPIApplication(fields.traceService, fields.auth, fields.benefit, fields.tenant, fields.workspace, fields.rateLimiter, fields.traceConfig, fields.metrics) + o := &OpenAPIApplication{ + traceService: fields.traceService, + auth: fields.auth, + benefit: fields.benefit, + tenant: fields.tenant, + workspace: fields.workspace, + rateLimiter: fields.rateLimiter.NewRateLimiter(), + traceConfig: fields.traceConfig, + metrics: fields.metrics, + } + err := error(nil) assert.NoError(t, err) got, err := o.ListSpansOApi(tt.args.ctx, tt.args.req) assert.Equal(t, tt.wantErr, err != nil) @@ -1526,10 +1811,20 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { rateLimiterMock.EXPECT().NewRateLimiter().Return(rateLimiterFactoryMock).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - traceConfigMock.EXPECT().GetQueryMaxQPSBySpace(gomock.Any(), int64(123)).Return(100, nil) + traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(100, nil) rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&limiter.Result{Allowed: true}, nil) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return(int64(123)) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() metricsMock.EXPECT().EmitSearchTraceOapi( int64(123), gomock.Any(), @@ -1583,10 +1878,20 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { rateLimiterMock.EXPECT().NewRateLimiter().Return(rateLimiterFactoryMock).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - traceConfigMock.EXPECT().GetQueryMaxQPSBySpace(gomock.Any(), int64(123)).Return(100, nil) + traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(100, nil) rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&limiter.Result{Allowed: true}, nil) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return(int64(123)) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() metricsMock.EXPECT().EmitSearchTraceOapi( int64(123), gomock.Any(), @@ -1631,6 +1936,17 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -1661,6 +1977,17 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -1704,6 +2031,17 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -1749,7 +2087,17 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return(int64(123)) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -1801,10 +2149,20 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { rateLimiterMock.EXPECT().NewRateLimiter().Return(rateLimiterFactoryMock).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - traceConfigMock.EXPECT().GetQueryMaxQPSBySpace(gomock.Any(), int64(123)).Return(100, nil) + traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(100, nil) rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&limiter.Result{Allowed: true}, nil) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return(int64(123)) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() metricsMock.EXPECT().EmitSearchTraceOapi( int64(123), gomock.Any(), @@ -1843,7 +2201,17 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() fields := tt.fieldsGetter(ctrl) - o, err := NewOpenAPIApplication(fields.traceService, fields.auth, fields.benefit, fields.tenant, fields.workspace, fields.rateLimiter, fields.traceConfig, fields.metrics) + o := &OpenAPIApplication{ + traceService: fields.traceService, + auth: fields.auth, + benefit: fields.benefit, + tenant: fields.tenant, + workspace: fields.workspace, + rateLimiter: fields.rateLimiter.NewRateLimiter(), + traceConfig: fields.traceConfig, + metrics: fields.metrics, + } + err := error(nil) assert.NoError(t, err) got, err := o.SearchTraceOApi(tt.args.ctx, tt.args.req) assert.Equal(t, tt.wantErr, err != nil) @@ -1903,7 +2271,17 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return(int64(123)) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterFactoryMock := limitermocks.NewMockIRateLimiter(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(rateLimiterFactoryMock).AnyTimes() @@ -1915,7 +2293,7 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { gomock.Any(), gomock.Any(), ).AnyTimes() - traceConfigMock.EXPECT().GetQueryMaxQPSBySpace(gomock.Any(), int64(123)).Return(100, nil) + traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(100, nil) rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&limiter.Result{Allowed: true}, nil) return fields{ traceService: traceServiceMock, @@ -1959,6 +2337,17 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -2000,6 +2389,17 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -2041,6 +2441,17 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -2083,7 +2494,17 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return(int64(123)) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -2126,7 +2547,17 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return(int64(123)) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterFactoryMock := limitermocks.NewMockIRateLimiter(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(rateLimiterFactoryMock).AnyTimes() @@ -2138,7 +2569,7 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { gomock.Any(), gomock.Any(), ).AnyTimes() - traceConfigMock.EXPECT().GetQueryMaxQPSBySpace(gomock.Any(), int64(123)).Return(100, nil) + traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(100, nil) rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&limiter.Result{Allowed: false}, nil) return fields{ traceService: traceServiceMock, @@ -2173,7 +2604,17 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return(int64(123)) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterFactoryMock := limitermocks.NewMockIRateLimiter(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(rateLimiterFactoryMock).AnyTimes() @@ -2185,7 +2626,7 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { gomock.Any(), gomock.Any(), ).AnyTimes() - traceConfigMock.EXPECT().GetQueryMaxQPSBySpace(gomock.Any(), int64(123)).Return(100, nil) + traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(100, nil) rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&limiter.Result{Allowed: true}, nil) return fields{ traceService: traceServiceMock, @@ -2217,7 +2658,17 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() fields := tt.fieldsGetter(ctrl) - o, err := NewOpenAPIApplication(fields.traceService, fields.auth, fields.benefit, fields.tenant, fields.workspace, fields.rateLimiter, fields.traceConfig, fields.metrics) + o := &OpenAPIApplication{ + traceService: fields.traceService, + auth: fields.auth, + benefit: fields.benefit, + tenant: fields.tenant, + workspace: fields.workspace, + rateLimiter: fields.rateLimiter.NewRateLimiter(), + traceConfig: fields.traceConfig, + metrics: fields.metrics, + } + err := error(nil) assert.NoError(t, err) got, err := o.ListTracesOApi(tt.args.ctx, tt.args.req) assert.Equal(t, tt.wantErr, err != nil) @@ -2262,6 +2713,17 @@ func TestOpenAPIApplication_unpackSpace(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -2291,7 +2753,14 @@ func TestOpenAPIApplication_unpackSpace(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("") + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -2323,8 +2792,19 @@ func TestOpenAPIApplication_unpackSpace(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("workspace1").Times(2) - workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("workspace2").Times(1) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + return "workspace1" + case "span2": + return "workspace1" + case "span3": + return "workspace2" + } } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -2365,9 +2845,19 @@ func TestOpenAPIApplication_unpackSpace(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() fields := tt.fieldsGetter(ctrl) - o, err := NewOpenAPIApplication(fields.traceService, fields.auth, fields.benefit, fields.tenant, fields.workspace, fields.rateLimiter, fields.traceConfig, fields.metrics) + o := &OpenAPIApplication{ + traceService: fields.traceService, + auth: fields.auth, + benefit: fields.benefit, + tenant: fields.tenant, + workspace: fields.workspace, + rateLimiter: fields.rateLimiter.NewRateLimiter(), + traceConfig: fields.traceConfig, + metrics: fields.metrics, + } + err := error(nil) assert.NoError(t, err) - got := o.(*OpenAPIApplication).unpackSpace(tt.args.ctx, tt.args.spans) + got := o.unpackSpace(tt.args.ctx, tt.args.spans) if tt.want == nil { assert.Nil(t, got) } else { @@ -2382,8 +2872,8 @@ func TestOpenAPIApplication_unpackSpace(t *testing.T) { } } -// TestOpenAPIApplication_AllowBySpace tests the AllowBySpace method -func TestOpenAPIApplication_AllowBySpace(t *testing.T) { +// TestOpenAPIApplication_AllowByKey tests the AllowByKey method +func TestOpenAPIApplication_AllowByKey(t *testing.T) { type fields struct { traceService service.ITraceService auth rpc.IAuthProvider @@ -2412,13 +2902,24 @@ func TestOpenAPIApplication_AllowBySpace(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterFactoryMock := limitermocks.NewMockIRateLimiter(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(rateLimiterFactoryMock).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - traceConfigMock.EXPECT().GetQueryMaxQPSBySpace(gomock.Any(), int64(123)).Return(100, nil) - rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), "query_trace:qps:space_id:123", 1, gomock.Any()).Return(&limiter.Result{Allowed: true}, nil) + traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(100, nil) + rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), "123", 1, gomock.Any()).Return(&limiter.Result{Allowed: true}, nil) return fields{ traceService: traceServiceMock, auth: authMock, @@ -2444,13 +2945,24 @@ func TestOpenAPIApplication_AllowBySpace(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterFactoryMock := limitermocks.NewMockIRateLimiter(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(rateLimiterFactoryMock).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - traceConfigMock.EXPECT().GetQueryMaxQPSBySpace(gomock.Any(), int64(123)).Return(100, nil) - rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), "query_trace:qps:space_id:123", 1, gomock.Any()).Return(&limiter.Result{Allowed: false}, nil) + traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(100, nil) + rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), "123", 1, gomock.Any()).Return(&limiter.Result{Allowed: false}, nil) return fields{ traceService: traceServiceMock, auth: authMock, @@ -2476,12 +2988,23 @@ func TestOpenAPIApplication_AllowBySpace(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterFactoryMock := limitermocks.NewMockIRateLimiter(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(rateLimiterFactoryMock).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - traceConfigMock.EXPECT().GetQueryMaxQPSBySpace(gomock.Any(), int64(123)).Return(0, assert.AnError) + traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(0, assert.AnError) return fields{ traceService: traceServiceMock, auth: authMock, @@ -2507,13 +3030,24 @@ func TestOpenAPIApplication_AllowBySpace(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterFactoryMock := limitermocks.NewMockIRateLimiter(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(rateLimiterFactoryMock).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - traceConfigMock.EXPECT().GetQueryMaxQPSBySpace(gomock.Any(), int64(123)).Return(100, nil) - rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), "query_trace:qps:space_id:123", 1, gomock.Any()).Return(nil, assert.AnError) + traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(100, nil) + rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), "123", 1, gomock.Any()).Return(nil, assert.AnError) return fields{ traceService: traceServiceMock, auth: authMock, @@ -2539,13 +3073,24 @@ func TestOpenAPIApplication_AllowBySpace(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { + if len(spans) > 0 { + switch spans[0].SpanID { + case "span1": + case "span2": + case "span3": + return "workspace2" } + } + return "" + }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterFactoryMock := limitermocks.NewMockIRateLimiter(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(rateLimiterFactoryMock).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - traceConfigMock.EXPECT().GetQueryMaxQPSBySpace(gomock.Any(), int64(123)).Return(100, nil) - rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), "query_trace:qps:space_id:123", 1, gomock.Any()).Return(nil, nil) + traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(100, nil) + rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), "123", 1, gomock.Any()).Return(nil, nil) return fields{ traceService: traceServiceMock, auth: authMock, @@ -2570,10 +3115,20 @@ func TestOpenAPIApplication_AllowBySpace(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() fields := tt.fieldsGetter(ctrl) - o, err := NewOpenAPIApplication(fields.traceService, fields.auth, fields.benefit, fields.tenant, fields.workspace, fields.rateLimiter, fields.traceConfig, fields.metrics) + o := &OpenAPIApplication{ + traceService: fields.traceService, + auth: fields.auth, + benefit: fields.benefit, + tenant: fields.tenant, + workspace: fields.workspace, + rateLimiter: fields.rateLimiter.NewRateLimiter(), + traceConfig: fields.traceConfig, + metrics: fields.metrics, + } + err := error(nil) assert.NoError(t, err) - got := o.(*OpenAPIApplication).AllowBySpace(tt.args.ctx, tt.args.workspaceID) + got := o.AllowByKey(tt.args.ctx, strconv.FormatInt(tt.args.workspaceID, 10)) assert.Equal(t, tt.want, got) }) } -} +} \ No newline at end of file From b648ccaf74f68fe17e2a393d1cf5303ecd5e4fbb Mon Sep 17 00:00:00 2001 From: cuichen Date: Thu, 4 Sep 2025 17:03:40 +0800 Subject: [PATCH 02/29] =?UTF-8?q?feat:=20[Coda]=20=E4=BF=AE=E5=A4=8DOpenAP?= =?UTF-8?q?I=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E8=B0=83=E7=94=A8=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Coda --- .../domain/component/workspace/mocks/workspace_provider.go | 4 ++-- .../observability/domain/component/workspace/workspace.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/modules/observability/domain/component/workspace/mocks/workspace_provider.go b/backend/modules/observability/domain/component/workspace/mocks/workspace_provider.go index e753c2a1b..f5a063378 100644 --- a/backend/modules/observability/domain/component/workspace/mocks/workspace_provider.go +++ b/backend/modules/observability/domain/component/workspace/mocks/workspace_provider.go @@ -56,10 +56,10 @@ func (mr *MockIWorkSpaceProviderMockRecorder) GetIngestWorkSpaceID(ctx, spans an } // GetQueryWorkSpaceID mocks base method. -func (m *MockIWorkSpaceProvider) GetQueryWorkSpaceID(ctx context.Context, requestWorkspaceID int64) int64 { +func (m *MockIWorkSpaceProvider) GetQueryWorkSpaceID(ctx context.Context, requestWorkspaceID int64) string { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetQueryWorkSpaceID", ctx, requestWorkspaceID) - ret0, _ := ret[0].(int64) + ret0, _ := ret[0].(string) return ret0 } diff --git a/backend/modules/observability/domain/component/workspace/workspace.go b/backend/modules/observability/domain/component/workspace/workspace.go index 50b7bc4dc..a4c81da65 100644 --- a/backend/modules/observability/domain/component/workspace/workspace.go +++ b/backend/modules/observability/domain/component/workspace/workspace.go @@ -12,5 +12,5 @@ import ( //go:generate mockgen -destination=mocks/workspace_provider.go -package=mocks . IWorkSpaceProvider type IWorkSpaceProvider interface { GetIngestWorkSpaceID(ctx context.Context, spans []*span.InputSpan) string - GetQueryWorkSpaceID(ctx context.Context, requestWorkspaceID int64) int64 + GetQueryWorkSpaceID(ctx context.Context, requestWorkspaceID int64) string } From 0f130e288a05ebb9b80a118148c2bf08e5b72058 Mon Sep 17 00:00:00 2001 From: cuichen Date: Thu, 4 Sep 2025 17:05:14 +0800 Subject: [PATCH 03/29] workspace upgrade --- backend/go.sum | 2 - .../observability/application/openapi.go | 59 ++++++++++--------- .../domain/component/config/config.go | 2 +- .../domain/component/config/mocks/config.go | 12 ++-- .../service/trace/span_processor/processor.go | 11 ++-- .../domain/trace/service/trace_service.go | 54 +++++++++-------- .../observability/infra/config/trace.go | 6 +- .../infra/workspace/workspace.go | 5 +- 8 files changed, 78 insertions(+), 73 deletions(-) diff --git a/backend/go.sum b/backend/go.sum index cba7b541b..2f5f99197 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -249,8 +249,6 @@ github.com/coocood/freecache v1.2.4/go.mod h1:RBUWa/Cy+OHdfTGFEhEuE1pMCMX51Ncizj github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/coze-dev/cozeloop-go v0.1.9 h1:4mb1x+uP0WNRG/safwWrOwm65T+qQsWOt+W8ZrZEFUU= -github.com/coze-dev/cozeloop-go v0.1.9/go.mod h1:RMH0F6ZMwZm4ZL92IHLjTf4lmr8QHxYJVPCdz60ZbbI= github.com/coze-dev/cozeloop-go v0.1.10-0.20250901062520-61d3699b1e83 h1:7Jh4flr9XqvissJtafWhTcs1vcErUcsjNkkniH/szxY= github.com/coze-dev/cozeloop-go v0.1.10-0.20250901062520-61d3699b1e83/go.mod h1:RMH0F6ZMwZm4ZL92IHLjTf4lmr8QHxYJVPCdz60ZbbI= github.com/coze-dev/cozeloop-go/spec v0.1.4-0.20250829072213-3812ddbfb735 h1:qxAwjHy0SLQazDO3oGJ8D24vOeM2Oz2+n27bNPegBls= diff --git a/backend/modules/observability/application/openapi.go b/backend/modules/observability/application/openapi.go index f6c75e9df..b629a506b 100644 --- a/backend/modules/observability/application/openapi.go +++ b/backend/modules/observability/application/openapi.go @@ -471,12 +471,12 @@ func (o *OpenAPIApplication) SearchTraceOApi(ctx context.Context, req *openapi.S errCode = obErrorx.CommercialCommonInvalidParamCodeCode return nil, err } - req.WorkspaceID = o.workspace.GetQueryWorkSpaceID(ctx, req.GetWorkspaceID()) if err = o.auth.CheckQueryPermission(ctx, strconv.FormatInt(req.GetWorkspaceID(), 10), req.GetPlatformType()); err != nil { errCode = obErrorx.CommonNoPermissionCode return nil, err } - if !o.AllowBySpace(ctx, req.GetWorkspaceID()) { + limitKey := strconv.FormatInt(req.GetWorkspaceID(), 10) + if !o.AllowByKey(ctx, limitKey) { err = errorx.NewByCode(obErrorx.CommonRequestRateLimitCode, errorx.WithExtraMsg("qps limit exceeded")) errCode = obErrorx.CommonRequestRateLimitCode return nil, err @@ -540,14 +540,15 @@ func (o *OpenAPIApplication) buildSearchTraceReq(ctx context.Context, req *opena } ret := &service.SearchTraceOApiReq{ - WorkspaceID: req.WorkspaceID, - Tenants: o.tenant.GetOAPIQueryTenants(ctx, platformType), - TraceID: req.GetTraceID(), - LogID: req.GetLogid(), - StartTime: req.GetStartTime(), - EndTime: req.GetEndTime(), - Limit: req.GetLimit(), - PlatformType: platformType, + WorkspaceID: req.WorkspaceID, + ThirdPartyWorkspaceID: o.workspace.GetQueryWorkSpaceID(ctx, req.WorkspaceID), + Tenants: o.tenant.GetOAPIQueryTenants(ctx, platformType), + TraceID: req.GetTraceID(), + LogID: req.GetLogid(), + StartTime: req.GetStartTime(), + EndTime: req.GetEndTime(), + Limit: req.GetLimit(), + PlatformType: platformType, } if len(ret.Tenants) == 0 { logs.CtxError(ctx, "fail to get platform tenants") @@ -570,13 +571,13 @@ func (o *OpenAPIApplication) ListSpansOApi(ctx context.Context, req *openapi.Lis errCode = obErrorx.CommercialCommonInvalidParamCodeCode return nil, err } - req.WorkspaceID = o.workspace.GetQueryWorkSpaceID(ctx, req.GetWorkspaceID()) if err = o.auth.CheckQueryPermission(ctx, strconv.FormatInt(req.GetWorkspaceID(), 10), req.GetPlatformType()); err != nil { errCode = obErrorx.CommonNoPermissionCode return nil, err } - if !o.AllowBySpace(ctx, req.GetWorkspaceID()) { + limitKey := strconv.FormatInt(req.GetWorkspaceID(), 10) + if !o.AllowByKey(ctx, limitKey) { err = errorx.NewByCode(obErrorx.CommonRequestRateLimitCode, errorx.WithExtraMsg("qps limit exceeded")) errCode = obErrorx.CommonRequestRateLimitCode return nil, err @@ -628,12 +629,13 @@ func (o *OpenAPIApplication) validateListSpansOApi(ctx context.Context, req *ope func (o *OpenAPIApplication) buildListSpansOApiReq(ctx context.Context, req *openapi.ListSpansOApiRequest) (*service.ListSpansOApiReq, error) { ret := &service.ListSpansOApiReq{ - WorkspaceID: req.WorkspaceID, - StartTime: req.GetStartTime(), - EndTime: req.GetEndTime(), - Limit: QueryLimitDefault, - DescByStartTime: len(req.GetOrderBys()) > 0, - PageToken: req.GetPageToken(), + WorkspaceID: req.WorkspaceID, + ThirdPartyWorkspaceID: o.workspace.GetQueryWorkSpaceID(ctx, req.WorkspaceID), + StartTime: req.GetStartTime(), + EndTime: req.GetEndTime(), + Limit: QueryLimitDefault, + DescByStartTime: len(req.GetOrderBys()) > 0, + PageToken: req.GetPageToken(), } if req.PageSize != nil { ret.Limit = *req.PageSize @@ -680,20 +682,20 @@ func (o *OpenAPIApplication) ListTracesOApi(ctx context.Context, req *openapi.Li errCode = obErrorx.CommercialCommonInvalidParamCodeCode return nil, err } - req.WorkspaceID = o.workspace.GetQueryWorkSpaceID(ctx, req.GetWorkspaceID()) if err = o.auth.CheckQueryPermission(ctx, strconv.FormatInt(req.GetWorkspaceID(), 10), req.GetPlatformType()); err != nil { errCode = obErrorx.CommonNoPermissionCode return nil, err } - if !o.AllowBySpace(ctx, req.GetWorkspaceID()) { + limitKey := strconv.FormatInt(req.GetWorkspaceID(), 10) + if !o.AllowByKey(ctx, limitKey) { err = errorx.NewByCode(obErrorx.CommonRequestRateLimitCode, errorx.WithExtraMsg("qps limit exceeded")) errCode = obErrorx.CommonRequestRateLimitCode return nil, err } logs.CtxInfo(ctx, "ListTracesOApi request: %+v", req) - sReq := o.buildListTracesOApiReq(req) + sReq := o.buildListTracesOApiReq(ctx, req) sResp, err := o.traceService.GetTracesAdvanceInfo(ctx, sReq) if err != nil { errCode = obErrorx.CommonInternalErrorCode @@ -738,10 +740,11 @@ func (o *OpenAPIApplication) validateListTracesOApiReq(ctx context.Context, req return nil } -func (o *OpenAPIApplication) buildListTracesOApiReq(req *openapi.ListTracesOApiRequest) *service.GetTracesAdvanceInfoReq { +func (o *OpenAPIApplication) buildListTracesOApiReq(ctx context.Context, req *openapi.ListTracesOApiRequest) *service.GetTracesAdvanceInfoReq { ret := &service.GetTracesAdvanceInfoReq{ - WorkspaceID: req.GetWorkspaceID(), - Traces: make([]*service.TraceQueryParam, len(req.GetTraceIds())), + WorkspaceID: req.GetWorkspaceID(), + ThirdPartyWorkspaceID: o.workspace.GetQueryWorkSpaceID(ctx, req.WorkspaceID), + Traces: make([]*service.TraceQueryParam, len(req.GetTraceIds())), } for i, id := range req.GetTraceIds() { ret.Traces[i] = &service.TraceQueryParam{ @@ -762,13 +765,13 @@ func (o *OpenAPIApplication) Send(ctx context.Context, event *entity.AnnotationE return o.traceService.Send(ctx, event) } -func (p *OpenAPIApplication) AllowBySpace(ctx context.Context, workspaceID int64) bool { - maxQPS, err := p.traceConfig.GetQueryMaxQPSBySpace(ctx, workspaceID) +func (p *OpenAPIApplication) AllowByKey(ctx context.Context, key string) bool { + maxQPS, err := p.traceConfig.GetQueryMaxQPS(ctx, key) if err != nil { - logs.CtxError(ctx, "get query max qps failed, err=%v, space_id=%d", err, workspaceID) + logs.CtxError(ctx, "get query max qps failed, err=%v, key=%s", err, key) return true } - result, err := p.rateLimiter.AllowN(ctx, fmt.Sprintf("query_trace:qps:space_id:%d", workspaceID), 1, + result, err := p.rateLimiter.AllowN(ctx, key, 1, limiter.WithLimit(&limiter.Limit{ Rate: maxQPS, Burst: maxQPS, diff --git a/backend/modules/observability/domain/component/config/config.go b/backend/modules/observability/domain/component/config/config.go index ad2d6a2c6..ea00b0efb 100644 --- a/backend/modules/observability/domain/component/config/config.go +++ b/backend/modules/observability/domain/component/config/config.go @@ -115,7 +115,7 @@ type ITraceConfig interface { GetTraceDataMaxDurationDay(ctx context.Context, platformType *string) int64 GetDefaultTraceTenant(ctx context.Context) string GetAnnotationSourceCfg(ctx context.Context) (*AnnotationSourceConfig, error) - GetQueryMaxQPSBySpace(ctx context.Context, workspaceID int64) (int, error) + GetQueryMaxQPS(ctx context.Context, key string) (int, error) conf.IConfigLoader } diff --git a/backend/modules/observability/domain/component/config/mocks/config.go b/backend/modules/observability/domain/component/config/mocks/config.go index b63baaf06..3e2d45000 100644 --- a/backend/modules/observability/domain/component/config/mocks/config.go +++ b/backend/modules/observability/domain/component/config/mocks/config.go @@ -130,19 +130,19 @@ func (mr *MockITraceConfigMockRecorder) GetPlatformTenants(ctx any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPlatformTenants", reflect.TypeOf((*MockITraceConfig)(nil).GetPlatformTenants), ctx) } -// GetQueryMaxQPSBySpace mocks base method. -func (m *MockITraceConfig) GetQueryMaxQPSBySpace(ctx context.Context, workspaceID int64) (int, error) { +// GetQueryMaxQPS mocks base method. +func (m *MockITraceConfig) GetQueryMaxQPS(ctx context.Context, key string) (int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetQueryMaxQPSBySpace", ctx, workspaceID) + ret := m.ctrl.Call(m, "GetQueryMaxQPS", ctx, key) ret0, _ := ret[0].(int) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetQueryMaxQPSBySpace indicates an expected call of GetQueryMaxQPSBySpace. -func (mr *MockITraceConfigMockRecorder) GetQueryMaxQPSBySpace(ctx, workspaceID any) *gomock.Call { +// GetQueryMaxQPS indicates an expected call of GetQueryMaxQPS. +func (mr *MockITraceConfigMockRecorder) GetQueryMaxQPS(ctx, key any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetQueryMaxQPSBySpace", reflect.TypeOf((*MockITraceConfig)(nil).GetQueryMaxQPSBySpace), ctx, workspaceID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetQueryMaxQPS", reflect.TypeOf((*MockITraceConfig)(nil).GetQueryMaxQPS), ctx, key) } // GetSystemViews mocks base method. diff --git a/backend/modules/observability/domain/trace/service/trace/span_processor/processor.go b/backend/modules/observability/domain/trace/service/trace/span_processor/processor.go index cd9ea0912..465542a9c 100644 --- a/backend/modules/observability/domain/trace/service/trace/span_processor/processor.go +++ b/backend/modules/observability/domain/trace/service/trace/span_processor/processor.go @@ -11,11 +11,12 @@ import ( type Settings struct { // query parameters - WorkspaceId int64 - PlatformType loop_span.PlatformType - QueryStartTime int64 // ms - QueryEndTime int64 // ms - Tenant string + WorkspaceId int64 + ThirdPartyWorkspaceID string + PlatformType loop_span.PlatformType + QueryStartTime int64 // ms + QueryEndTime int64 // ms + Tenant string } type Factory interface { diff --git a/backend/modules/observability/domain/trace/service/trace_service.go b/backend/modules/observability/domain/trace/service/trace_service.go index b37f12ce8..c4803c335 100644 --- a/backend/modules/observability/domain/trace/service/trace_service.go +++ b/backend/modules/observability/domain/trace/service/trace_service.go @@ -64,14 +64,15 @@ type GetTraceResp struct { } type SearchTraceOApiReq struct { - WorkspaceID int64 - Tenants []string - TraceID string - LogID string - StartTime int64 // ms - EndTime int64 // ms - Limit int32 - PlatformType loop_span.PlatformType + WorkspaceID int64 + ThirdPartyWorkspaceID string + Tenants []string + TraceID string + LogID string + StartTime int64 // ms + EndTime int64 // ms + Limit int32 + PlatformType loop_span.PlatformType } type SearchTraceOApiResp struct { @@ -79,16 +80,17 @@ type SearchTraceOApiResp struct { } type ListSpansOApiReq struct { - WorkspaceID int64 - Tenants []string - StartTime int64 // ms - EndTime int64 // ms - Filters *loop_span.FilterFields - Limit int32 - DescByStartTime bool - PageToken string - PlatformType loop_span.PlatformType - SpanListType loop_span.SpanListType + WorkspaceID int64 + ThirdPartyWorkspaceID string + Tenants []string + StartTime int64 // ms + EndTime int64 // ms + Filters *loop_span.FilterFields + Limit int32 + DescByStartTime bool + PageToken string + PlatformType loop_span.PlatformType + SpanListType loop_span.SpanListType } type ListSpansOApiResp struct { @@ -104,9 +106,10 @@ type TraceQueryParam struct { } type GetTracesAdvanceInfoReq struct { - WorkspaceID int64 - Traces []*TraceQueryParam - PlatformType loop_span.PlatformType + WorkspaceID int64 + ThirdPartyWorkspaceID string + Traces []*TraceQueryParam + PlatformType loop_span.PlatformType } type GetTracesAdvanceInfoResp struct { @@ -354,10 +357,11 @@ func (r *TraceServiceImpl) SearchTraceOApi(ctx context.Context, req *SearchTrace return nil, err } processors, err := r.buildHelper.BuildSearchTraceOApiProcessors(ctx, span_processor.Settings{ - WorkspaceId: req.WorkspaceID, - QueryStartTime: req.StartTime, - QueryEndTime: req.EndTime, - PlatformType: req.PlatformType, + WorkspaceId: req.WorkspaceID, + ThirdPartyWorkspaceID: req.ThirdPartyWorkspaceID, + QueryStartTime: req.StartTime, + QueryEndTime: req.EndTime, + PlatformType: req.PlatformType, }) if err != nil { return nil, errorx.WrapByCode(err, obErrorx.CommercialCommonInternalErrorCodeCode) diff --git a/backend/modules/observability/infra/config/trace.go b/backend/modules/observability/infra/config/trace.go index 707e4df3d..18f22c036 100644 --- a/backend/modules/observability/infra/config/trace.go +++ b/backend/modules/observability/infra/config/trace.go @@ -6,8 +6,6 @@ package config import ( "context" "fmt" - "strconv" - "github.com/coze-dev/coze-loop/backend/modules/observability/domain/component/config" "github.com/coze-dev/coze-loop/backend/pkg/conf" "github.com/coze-dev/coze-loop/backend/pkg/logs" @@ -141,12 +139,12 @@ func (t *TraceConfigCenter) GetAnnotationSourceCfg(ctx context.Context) (*config return annotationSourceCfg, nil } -func (t *TraceConfigCenter) GetQueryMaxQPSBySpace(ctx context.Context, workspaceID int64) (int, error) { +func (t *TraceConfigCenter) GetQueryMaxQPS(ctx context.Context, key string) (int, error) { qpsConfig := new(config.QueryTraceRateLimitConfig) if err := t.UnmarshalKey(ctx, queryTraceRateLimitCfgKey, &qpsConfig); err != nil { return 0, err } - if qps, ok := qpsConfig.SpaceMaxQPS[strconv.FormatInt(workspaceID, 10)]; ok { + if qps, ok := qpsConfig.SpaceMaxQPS[key]; ok { return qps, nil } return qpsConfig.DefaultMaxQPS, nil diff --git a/backend/modules/observability/infra/workspace/workspace.go b/backend/modules/observability/infra/workspace/workspace.go index fcf35a0f4..ca3e7ae1c 100644 --- a/backend/modules/observability/infra/workspace/workspace.go +++ b/backend/modules/observability/infra/workspace/workspace.go @@ -5,6 +5,7 @@ package workspace import ( "context" + "strconv" "github.com/coze-dev/coze-loop/backend/kitex_gen/coze/loop/observability/domain/span" "github.com/coze-dev/coze-loop/backend/modules/observability/domain/component/workspace" @@ -23,6 +24,6 @@ func (t *WorkspaceProviderImpl) GetIngestWorkSpaceID(ctx context.Context, spans return spans[0].WorkspaceID } -func (t *WorkspaceProviderImpl) GetQueryWorkSpaceID(ctx context.Context, requestWorkspaceID int64) int64 { - return requestWorkspaceID +func (t *WorkspaceProviderImpl) GetQueryWorkSpaceID(ctx context.Context, requestWorkspaceID int64) string { + return strconv.FormatInt(requestWorkspaceID, 10) } From b4330c8e64f3bb5eb33473d614d4f1523a98bda0 Mon Sep 17 00:00:00 2001 From: cuichen Date: Thu, 4 Sep 2025 19:16:08 +0800 Subject: [PATCH 04/29] workspace upgrade --- .../trace/service/trace/span_filter/filter.go | 3 ++- .../domain/trace/service/trace_service.go | 27 ++++++++++--------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/backend/modules/observability/domain/trace/service/trace/span_filter/filter.go b/backend/modules/observability/domain/trace/service/trace/span_filter/filter.go index 34a5d542b..e1e757abc 100644 --- a/backend/modules/observability/domain/trace/service/trace/span_filter/filter.go +++ b/backend/modules/observability/domain/trace/service/trace/span_filter/filter.go @@ -12,7 +12,8 @@ import ( ) type SpanEnv struct { - WorkspaceId int64 + WorkspaceId int64 + ThirdPartyWorkspaceID string } type Factory interface { diff --git a/backend/modules/observability/domain/trace/service/trace_service.go b/backend/modules/observability/domain/trace/service/trace_service.go index c4803c335..72c9ce491 100644 --- a/backend/modules/observability/domain/trace/service/trace_service.go +++ b/backend/modules/observability/domain/trace/service/trace_service.go @@ -31,15 +31,16 @@ import ( ) type ListSpansReq struct { - WorkspaceID int64 - StartTime int64 // ms - EndTime int64 // ms - Filters *loop_span.FilterFields - Limit int32 - DescByStartTime bool - PageToken string - PlatformType loop_span.PlatformType - SpanListType loop_span.SpanListType + WorkspaceID int64 + ThirdPartyWorkspaceID string + StartTime int64 // ms + EndTime int64 // ms + Filters *loop_span.FilterFields + Limit int32 + DescByStartTime bool + PageToken string + PlatformType loop_span.PlatformType + SpanListType loop_span.SpanListType } type ListSpansResp struct { @@ -387,8 +388,9 @@ func (r *TraceServiceImpl) ListSpansOApi(ctx context.Context, req *ListSpansOApi return nil, err } builtinFilter, err := r.buildBuiltinFilters(ctx, platformFilter, &ListSpansReq{ - WorkspaceID: req.WorkspaceID, - SpanListType: req.SpanListType, + WorkspaceID: req.WorkspaceID, + ThirdPartyWorkspaceID: req.ThirdPartyWorkspaceID, + SpanListType: req.SpanListType, }) if err != nil { return nil, err @@ -924,7 +926,8 @@ func (r *TraceServiceImpl) getAnnotationCallerCfg(ctx context.Context, caller st func (r *TraceServiceImpl) buildBuiltinFilters(ctx context.Context, f span_filter.Filter, req *ListSpansReq) (*loop_span.FilterFields, error) { filters := make([]*loop_span.FilterField, 0) env := &span_filter.SpanEnv{ - WorkspaceId: req.WorkspaceID, + WorkspaceId: req.WorkspaceID, + ThirdPartyWorkspaceID: req.ThirdPartyWorkspaceID, } basicFilter, forceQuery, err := f.BuildBasicSpanFilter(ctx, env) if err != nil { From 4661b46ad71dc010843b89738cd02b628c0cc5a9 Mon Sep 17 00:00:00 2001 From: cuichen Date: Thu, 4 Sep 2025 21:55:52 +0800 Subject: [PATCH 05/29] workspace upgrade --- .../observability/domain/trace/k-trace.go | 24 ++++---- .../loop/observability/domain/trace/trace.go | 56 +++++++++---------- .../application/convertor/trace/trace.go | 4 +- 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/backend/kitex_gen/coze/loop/observability/domain/trace/k-trace.go b/backend/kitex_gen/coze/loop/observability/domain/trace/k-trace.go index 4f0812316..9fcc649d2 100644 --- a/backend/kitex_gen/coze/loop/observability/domain/trace/k-trace.go +++ b/backend/kitex_gen/coze/loop/observability/domain/trace/k-trace.go @@ -203,8 +203,8 @@ func (p *TokenCost) FastRead(buf []byte) (int, error) { var l int var fieldTypeId thrift.TType var fieldId int16 - var issetInput bool = false - var issetOutput bool = false + var issetInputToken bool = false + var issetOutputToken bool = false for { fieldTypeId, fieldId, l, err = thrift.Binary.ReadFieldBegin(buf[offset:]) offset += l @@ -222,7 +222,7 @@ func (p *TokenCost) FastRead(buf []byte) (int, error) { if err != nil { goto ReadFieldError } - issetInput = true + issetInputToken = true } else { l, err = thrift.Binary.Skip(buf[offset:], fieldTypeId) offset += l @@ -237,7 +237,7 @@ func (p *TokenCost) FastRead(buf []byte) (int, error) { if err != nil { goto ReadFieldError } - issetOutput = true + issetOutputToken = true } else { l, err = thrift.Binary.Skip(buf[offset:], fieldTypeId) offset += l @@ -254,12 +254,12 @@ func (p *TokenCost) FastRead(buf []byte) (int, error) { } } - if !issetInput { + if !issetInputToken { fieldId = 1 goto RequiredFieldNotSetError } - if !issetOutput { + if !issetOutputToken { fieldId = 2 goto RequiredFieldNotSetError } @@ -284,7 +284,7 @@ func (p *TokenCost) FastReadField1(buf []byte) (int, error) { offset += l _field = v } - p.Input = _field + p.InputToken = _field return offset, nil } @@ -298,7 +298,7 @@ func (p *TokenCost) FastReadField2(buf []byte) (int, error) { offset += l _field = v } - p.Output = _field + p.OutputToken = _field return offset, nil } @@ -329,14 +329,14 @@ func (p *TokenCost) BLength() int { func (p *TokenCost) fastWriteField1(buf []byte, w thrift.NocopyWriter) int { offset := 0 offset += thrift.Binary.WriteFieldBegin(buf[offset:], thrift.I64, 1) - offset += thrift.Binary.WriteI64(buf[offset:], p.Input) + offset += thrift.Binary.WriteI64(buf[offset:], p.InputToken) return offset } func (p *TokenCost) fastWriteField2(buf []byte, w thrift.NocopyWriter) int { offset := 0 offset += thrift.Binary.WriteFieldBegin(buf[offset:], thrift.I64, 2) - offset += thrift.Binary.WriteI64(buf[offset:], p.Output) + offset += thrift.Binary.WriteI64(buf[offset:], p.OutputToken) return offset } @@ -360,9 +360,9 @@ func (p *TokenCost) DeepCopy(s interface{}) error { return fmt.Errorf("%T's type not matched %T", s, p) } - p.Input = src.Input + p.InputToken = src.InputToken - p.Output = src.Output + p.OutputToken = src.OutputToken return nil } diff --git a/backend/kitex_gen/coze/loop/observability/domain/trace/trace.go b/backend/kitex_gen/coze/loop/observability/domain/trace/trace.go index c9fc5c24a..89b63dc07 100644 --- a/backend/kitex_gen/coze/loop/observability/domain/trace/trace.go +++ b/backend/kitex_gen/coze/loop/observability/domain/trace/trace.go @@ -259,8 +259,8 @@ func (p *Trace) Field2DeepEqual(src *TokenCost) bool { } type TokenCost struct { - Input int64 `thrift:"input,1,required" frugal:"1,required,i64" json:"input" form:"input,required" query:"input,required"` - Output int64 `thrift:"output,2,required" frugal:"2,required,i64" json:"output" form:"output,required" query:"output,required"` + InputToken int64 `thrift:"input_token,1,required" frugal:"1,required,i64" json:"input_token" form:"input_token,required" query:"input_token,required"` + OutputToken int64 `thrift:"output_token,2,required" frugal:"2,required,i64" json:"output_token" form:"output_token,required" query:"output_token,required"` } func NewTokenCost() *TokenCost { @@ -270,36 +270,36 @@ func NewTokenCost() *TokenCost { func (p *TokenCost) InitDefault() { } -func (p *TokenCost) GetInput() (v int64) { +func (p *TokenCost) GetInputToken() (v int64) { if p != nil { - return p.Input + return p.InputToken } return } -func (p *TokenCost) GetOutput() (v int64) { +func (p *TokenCost) GetOutputToken() (v int64) { if p != nil { - return p.Output + return p.OutputToken } return } -func (p *TokenCost) SetInput(val int64) { - p.Input = val +func (p *TokenCost) SetInputToken(val int64) { + p.InputToken = val } -func (p *TokenCost) SetOutput(val int64) { - p.Output = val +func (p *TokenCost) SetOutputToken(val int64) { + p.OutputToken = val } var fieldIDToName_TokenCost = map[int16]string{ - 1: "input", - 2: "output", + 1: "input_token", + 2: "output_token", } func (p *TokenCost) Read(iprot thrift.TProtocol) (err error) { var fieldTypeId thrift.TType var fieldId int16 - var issetInput bool = false - var issetOutput bool = false + var issetInputToken bool = false + var issetOutputToken bool = false if _, err = iprot.ReadStructBegin(); err != nil { goto ReadStructBeginError @@ -320,7 +320,7 @@ func (p *TokenCost) Read(iprot thrift.TProtocol) (err error) { if err = p.ReadField1(iprot); err != nil { goto ReadFieldError } - issetInput = true + issetInputToken = true } else if err = iprot.Skip(fieldTypeId); err != nil { goto SkipFieldError } @@ -329,7 +329,7 @@ func (p *TokenCost) Read(iprot thrift.TProtocol) (err error) { if err = p.ReadField2(iprot); err != nil { goto ReadFieldError } - issetOutput = true + issetOutputToken = true } else if err = iprot.Skip(fieldTypeId); err != nil { goto SkipFieldError } @@ -346,12 +346,12 @@ func (p *TokenCost) Read(iprot thrift.TProtocol) (err error) { goto ReadStructEndError } - if !issetInput { + if !issetInputToken { fieldId = 1 goto RequiredFieldNotSetError } - if !issetOutput { + if !issetOutputToken { fieldId = 2 goto RequiredFieldNotSetError } @@ -381,7 +381,7 @@ func (p *TokenCost) ReadField1(iprot thrift.TProtocol) error { } else { _field = v } - p.Input = _field + p.InputToken = _field return nil } func (p *TokenCost) ReadField2(iprot thrift.TProtocol) error { @@ -392,7 +392,7 @@ func (p *TokenCost) ReadField2(iprot thrift.TProtocol) error { } else { _field = v } - p.Output = _field + p.OutputToken = _field return nil } @@ -429,10 +429,10 @@ WriteStructEndError: } func (p *TokenCost) writeField1(oprot thrift.TProtocol) (err error) { - if err = oprot.WriteFieldBegin("input", thrift.I64, 1); err != nil { + if err = oprot.WriteFieldBegin("input_token", thrift.I64, 1); err != nil { goto WriteFieldBeginError } - if err := oprot.WriteI64(p.Input); err != nil { + if err := oprot.WriteI64(p.InputToken); err != nil { return err } if err = oprot.WriteFieldEnd(); err != nil { @@ -445,10 +445,10 @@ WriteFieldEndError: return thrift.PrependError(fmt.Sprintf("%T write field 1 end error: ", p), err) } func (p *TokenCost) writeField2(oprot thrift.TProtocol) (err error) { - if err = oprot.WriteFieldBegin("output", thrift.I64, 2); err != nil { + if err = oprot.WriteFieldBegin("output_token", thrift.I64, 2); err != nil { goto WriteFieldBeginError } - if err := oprot.WriteI64(p.Output); err != nil { + if err := oprot.WriteI64(p.OutputToken); err != nil { return err } if err = oprot.WriteFieldEnd(); err != nil { @@ -475,10 +475,10 @@ func (p *TokenCost) DeepEqual(ano *TokenCost) bool { } else if p == nil || ano == nil { return false } - if !p.Field1DeepEqual(ano.Input) { + if !p.Field1DeepEqual(ano.InputToken) { return false } - if !p.Field2DeepEqual(ano.Output) { + if !p.Field2DeepEqual(ano.OutputToken) { return false } return true @@ -486,14 +486,14 @@ func (p *TokenCost) DeepEqual(ano *TokenCost) bool { func (p *TokenCost) Field1DeepEqual(src int64) bool { - if p.Input != src { + if p.InputToken != src { return false } return true } func (p *TokenCost) Field2DeepEqual(src int64) bool { - if p.Output != src { + if p.OutputToken != src { return false } return true diff --git a/backend/modules/observability/application/convertor/trace/trace.go b/backend/modules/observability/application/convertor/trace/trace.go index 0ad0f4998..422769a45 100644 --- a/backend/modules/observability/application/convertor/trace/trace.go +++ b/backend/modules/observability/application/convertor/trace/trace.go @@ -34,8 +34,8 @@ func AdvanceInfoDO2TraceDTO(info *loop_span.TraceAdvanceInfo) *traced.Trace { return &traced.Trace{ TraceID: &info.TraceId, Tokens: &traced.TokenCost{ - Input: info.InputCost, - Output: info.OutputCost, + InputToken: info.InputCost, + OutputToken: info.OutputCost, }, } } From 381e03b306c58ca3c22cbc52005eb2f61b12eb11 Mon Sep 17 00:00:00 2001 From: cuichen Date: Fri, 5 Sep 2025 16:07:17 +0800 Subject: [PATCH 06/29] workspace upgrade --- backend/modules/observability/infra/rpc/auth/auth.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/modules/observability/infra/rpc/auth/auth.go b/backend/modules/observability/infra/rpc/auth/auth.go index d8b8c58c2..4b1195939 100644 --- a/backend/modules/observability/infra/rpc/auth/auth.go +++ b/backend/modules/observability/infra/rpc/auth/auth.go @@ -118,7 +118,8 @@ func (a *AuthProviderImpl) CheckIngestPermission(ctx context.Context, workspaceI } func (a *AuthProviderImpl) CheckQueryPermission(ctx context.Context, workspaceId, platformType string) error { - return a.CheckWorkspacePermission(ctx, rpc.AuthActionTraceRead, workspaceId) + // todo test + return a.CheckWorkspacePermission(ctx, rpc.AuthActionTraceIngest, workspaceId) } func NewAuthProvider(cli authservice.Client) rpc.IAuthProvider { From c6476fc408f779bcbd99a6030fcc82dbae8cf133 Mon Sep 17 00:00:00 2001 From: cuichen Date: Fri, 5 Sep 2025 16:53:27 +0800 Subject: [PATCH 07/29] workspace upgrade --- backend/modules/observability/domain/component/rpc/auth.go | 1 + backend/modules/observability/infra/rpc/auth/auth.go | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/modules/observability/domain/component/rpc/auth.go b/backend/modules/observability/domain/component/rpc/auth.go index 6340f78f7..9f9ffcb7a 100644 --- a/backend/modules/observability/domain/component/rpc/auth.go +++ b/backend/modules/observability/domain/component/rpc/auth.go @@ -8,6 +8,7 @@ import "context" const ( AuthActionTraceRead = "readLoopTrace" AuthActionTraceIngest = "ingestLoopTrace" + AuthActionTraceList = "listLoopTrace" AuthActionTraceViewCreate = "createLoopTraceView" AuthActionTraceViewList = "listLoopTraceView" AuthActionTraceViewEdit = "edit" diff --git a/backend/modules/observability/infra/rpc/auth/auth.go b/backend/modules/observability/infra/rpc/auth/auth.go index 4b1195939..287ec809c 100644 --- a/backend/modules/observability/infra/rpc/auth/auth.go +++ b/backend/modules/observability/infra/rpc/auth/auth.go @@ -118,8 +118,7 @@ func (a *AuthProviderImpl) CheckIngestPermission(ctx context.Context, workspaceI } func (a *AuthProviderImpl) CheckQueryPermission(ctx context.Context, workspaceId, platformType string) error { - // todo test - return a.CheckWorkspacePermission(ctx, rpc.AuthActionTraceIngest, workspaceId) + return a.CheckWorkspacePermission(ctx, rpc.AuthActionTraceList, workspaceId) } func NewAuthProvider(cli authservice.Client) rpc.IAuthProvider { From e2faa587ea7eb26f612d588b7b1c7093f7b7c244 Mon Sep 17 00:00:00 2001 From: cuichen Date: Mon, 8 Sep 2025 11:47:28 +0800 Subject: [PATCH 08/29] add openapi resp.base --- .../modules/observability/application/openapi.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/backend/modules/observability/application/openapi.go b/backend/modules/observability/application/openapi.go index b629a506b..591df5377 100644 --- a/backend/modules/observability/application/openapi.go +++ b/backend/modules/observability/application/openapi.go @@ -562,6 +562,7 @@ func (o *OpenAPIApplication) ListSpansOApi(ctx context.Context, req *openapi.Lis st := time.Now() spansSize := 0 errCode := 0 + resq := openapi.NewListSpansOApiResponse() defer func() { if req != nil { o.metrics.EmitListSpansOapi(req.WorkspaceID, req.GetPlatformType(), req.GetSpanListType(), int64(spansSize), errCode, st, err != nil) @@ -596,13 +597,11 @@ func (o *OpenAPIApplication) ListSpansOApi(ctx context.Context, req *openapi.Lis logs.CtxInfo(ctx, "List spans successfully, spans count: %d", len(sResp.Spans)) spansSize = loop_span.SizeofSpans(sResp.Spans) } - return &openapi.ListSpansOApiResponse{ - Data: &openapi.ListSpansOApiData{ - Spans: tconv.SpanListDO2DTO(sResp.Spans, nil, nil, nil), - NextPageToken: sResp.NextPageToken, - HasMore: sResp.HasMore, - }, - }, nil + + resq.Data.Spans = tconv.SpanListDO2DTO(sResp.Spans, nil, nil, nil) + resq.Data.NextPageToken = sResp.NextPageToken + resq.Data.HasMore = sResp.HasMore + return resq, nil } func (o *OpenAPIApplication) validateListSpansOApi(ctx context.Context, req *openapi.ListSpansOApiRequest) error { From e0500f80beb99d4a853e26fbfb5a2ae8fcb0d52f Mon Sep 17 00:00:00 2001 From: cuichen Date: Mon, 8 Sep 2025 11:56:32 +0800 Subject: [PATCH 09/29] add openapi resp.base --- backend/modules/observability/application/openapi.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/backend/modules/observability/application/openapi.go b/backend/modules/observability/application/openapi.go index 591df5377..0344cc66b 100644 --- a/backend/modules/observability/application/openapi.go +++ b/backend/modules/observability/application/openapi.go @@ -598,9 +598,11 @@ func (o *OpenAPIApplication) ListSpansOApi(ctx context.Context, req *openapi.Lis spansSize = loop_span.SizeofSpans(sResp.Spans) } - resq.Data.Spans = tconv.SpanListDO2DTO(sResp.Spans, nil, nil, nil) - resq.Data.NextPageToken = sResp.NextPageToken - resq.Data.HasMore = sResp.HasMore + resq.Data = &openapi.ListSpansOApiData{ + Spans: tconv.SpanListDO2DTO(sResp.Spans, nil, nil, nil), + NextPageToken: sResp.NextPageToken, + HasMore: sResp.HasMore, + } return resq, nil } From a1dee4b7ad14f467f262e07502d751dcf72f4c1e Mon Sep 17 00:00:00 2001 From: cuichen Date: Mon, 8 Sep 2025 13:15:03 +0800 Subject: [PATCH 10/29] add openapi resp.base --- backend/modules/observability/application/openapi.go | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/modules/observability/application/openapi.go b/backend/modules/observability/application/openapi.go index 0344cc66b..3e1aa73de 100644 --- a/backend/modules/observability/application/openapi.go +++ b/backend/modules/observability/application/openapi.go @@ -603,6 +603,7 @@ func (o *OpenAPIApplication) ListSpansOApi(ctx context.Context, req *openapi.Lis NextPageToken: sResp.NextPageToken, HasMore: sResp.HasMore, } + resq.BaseResp = openapi.ListSpansOApiResponse_BaseResp_DEFAULT return resq, nil } From f5caeaf3dae41e34d6fcbafdb5a3dc8fbb14ca7a Mon Sep 17 00:00:00 2001 From: cuichen Date: Mon, 8 Sep 2025 13:27:25 +0800 Subject: [PATCH 11/29] add openapi resp.base --- backend/modules/observability/application/openapi.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/modules/observability/application/openapi.go b/backend/modules/observability/application/openapi.go index 3e1aa73de..0078340b3 100644 --- a/backend/modules/observability/application/openapi.go +++ b/backend/modules/observability/application/openapi.go @@ -9,6 +9,7 @@ import ( "context" "errors" "fmt" + "github.com/coze-dev/coze-loop/backend/kitex_gen/base" "io" "strconv" "strings" @@ -603,7 +604,7 @@ func (o *OpenAPIApplication) ListSpansOApi(ctx context.Context, req *openapi.Lis NextPageToken: sResp.NextPageToken, HasMore: sResp.HasMore, } - resq.BaseResp = openapi.ListSpansOApiResponse_BaseResp_DEFAULT + resq.BaseResp = &base.BaseResp{} return resq, nil } From a917b776f2f5b6581b9227602184dd138bd0934a Mon Sep 17 00:00:00 2001 From: cuichen Date: Mon, 8 Sep 2025 13:34:00 +0800 Subject: [PATCH 12/29] add openapi resp.base --- backend/modules/observability/application/openapi.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/modules/observability/application/openapi.go b/backend/modules/observability/application/openapi.go index 0078340b3..702196ae3 100644 --- a/backend/modules/observability/application/openapi.go +++ b/backend/modules/observability/application/openapi.go @@ -563,7 +563,7 @@ func (o *OpenAPIApplication) ListSpansOApi(ctx context.Context, req *openapi.Lis st := time.Now() spansSize := 0 errCode := 0 - resq := openapi.NewListSpansOApiResponse() + resp := openapi.NewListSpansOApiResponse() defer func() { if req != nil { o.metrics.EmitListSpansOapi(req.WorkspaceID, req.GetPlatformType(), req.GetSpanListType(), int64(spansSize), errCode, st, err != nil) @@ -599,13 +599,13 @@ func (o *OpenAPIApplication) ListSpansOApi(ctx context.Context, req *openapi.Lis spansSize = loop_span.SizeofSpans(sResp.Spans) } - resq.Data = &openapi.ListSpansOApiData{ + resp.Data = &openapi.ListSpansOApiData{ Spans: tconv.SpanListDO2DTO(sResp.Spans, nil, nil, nil), NextPageToken: sResp.NextPageToken, HasMore: sResp.HasMore, } - resq.BaseResp = &base.BaseResp{} - return resq, nil + resp.BaseResp = base.NewBaseResp() + return resp, nil } func (o *OpenAPIApplication) validateListSpansOApi(ctx context.Context, req *openapi.ListSpansOApiRequest) error { From 80b0027c5ef4a6c10e6561b0bca045a1ae04b677 Mon Sep 17 00:00:00 2001 From: cuichen Date: Mon, 8 Sep 2025 14:19:53 +0800 Subject: [PATCH 13/29] add openapi resp.base --- .../loop/observability/coze.loop.observability.openapi.thrift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idl/thrift/coze/loop/observability/coze.loop.observability.openapi.thrift b/idl/thrift/coze/loop/observability/coze.loop.observability.openapi.thrift index 5126f3560..58bf8eeca 100644 --- a/idl/thrift/coze/loop/observability/coze.loop.observability.openapi.thrift +++ b/idl/thrift/coze/loop/observability/coze.loop.observability.openapi.thrift @@ -146,7 +146,7 @@ service OpenAPIService { OtelIngestTracesResponse OtelIngestTraces(1: OtelIngestTracesRequest req) (api.post = '/v1/loop/opentelemetry/v1/traces') SearchTraceOApiResponse SearchTraceOApi(1: SearchTraceOApiRequest req) (api.post = '/v1/loop/traces/search') ListSpansOApiResponse ListSpansOApi(1: ListSpansOApiRequest req) (api.post = '/v1/loop/spans/search', api.tag="openapi") - ListTracesOApiResponse ListTracesOApi(1: ListTracesOApiRequest req) (api.post = '/v1/loop/traces/list') + ListTracesOApiResponse ListTracesOApi(1: ListTracesOApiRequest req) (api.post = '/v1/loop/traces/list', api.tag="openapi") CreateAnnotationResponse CreateAnnotation(1: CreateAnnotationRequest req) DeleteAnnotationResponse DeleteAnnotation(1: DeleteAnnotationRequest req) } \ No newline at end of file From 61fc5e1d24dcf9bcd362d9cf64d732ec5d25d006 Mon Sep 17 00:00:00 2001 From: cuichen Date: Mon, 8 Sep 2025 20:40:33 +0800 Subject: [PATCH 14/29] fix Golang CI Lint --- .../observability/application/openapi.go | 3 +- .../observability/application/openapi_test.go | 139 ++++++++++++------ .../observability/infra/config/trace.go | 1 + 3 files changed, 96 insertions(+), 47 deletions(-) diff --git a/backend/modules/observability/application/openapi.go b/backend/modules/observability/application/openapi.go index 702196ae3..931c64547 100644 --- a/backend/modules/observability/application/openapi.go +++ b/backend/modules/observability/application/openapi.go @@ -9,7 +9,7 @@ import ( "context" "errors" "fmt" - "github.com/coze-dev/coze-loop/backend/kitex_gen/base" + "io" "strconv" "strings" @@ -17,6 +17,7 @@ import ( "github.com/bytedance/gg/gptr" "github.com/bytedance/sonic" + "github.com/coze-dev/coze-loop/backend/kitex_gen/base" coltracepb "go.opentelemetry.io/proto/otlp/collector/trace/v1" "google.golang.org/protobuf/proto" diff --git a/backend/modules/observability/application/openapi_test.go b/backend/modules/observability/application/openapi_test.go index 9879d1fac..2b53b878d 100644 --- a/backend/modules/observability/application/openapi_test.go +++ b/backend/modules/observability/application/openapi_test.go @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 package application + import ( "bytes" "compress/gzip" @@ -45,6 +46,7 @@ import ( servicemocks "github.com/coze-dev/coze-loop/backend/modules/observability/domain/trace/service/mocks" "github.com/coze-dev/coze-loop/backend/pkg/lang/ptr" ) + func TestOpenAPIApplication_IngestTraces(t *testing.T) { type fields struct { traceService service.ITraceService @@ -212,7 +214,8 @@ func TestOpenAPIApplication_CreateAnnotation(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -258,7 +261,8 @@ func TestOpenAPIApplication_CreateAnnotation(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -355,7 +359,8 @@ func TestOpenAPIApplication_DeleteAnnotation(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -446,7 +451,8 @@ func TestOpenAPIApplication_Send(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -541,7 +547,8 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -599,7 +606,8 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -657,7 +665,8 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -711,7 +720,8 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -760,7 +770,8 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -801,7 +812,8 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -847,7 +859,8 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -893,7 +906,8 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -939,7 +953,8 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -985,7 +1000,8 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -1032,7 +1048,8 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -1079,7 +1096,8 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -1132,7 +1150,8 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -1185,7 +1204,8 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -1240,7 +1260,8 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -1464,7 +1485,8 @@ func TestOpenAPIApplication_ListSpansOApi(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -1528,7 +1550,8 @@ func TestOpenAPIApplication_ListSpansOApi(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -1584,7 +1607,8 @@ func TestOpenAPIApplication_ListSpansOApi(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -1646,7 +1670,8 @@ func TestOpenAPIApplication_ListSpansOApi(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -1706,7 +1731,8 @@ func TestOpenAPIApplication_ListSpansOApi(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -1821,7 +1847,8 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -1888,7 +1915,8 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -1943,7 +1971,8 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -1984,7 +2013,8 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -2038,7 +2068,8 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -2094,7 +2125,8 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -2159,7 +2191,8 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -2278,7 +2311,8 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -2344,7 +2378,8 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -2396,7 +2431,8 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -2448,7 +2484,8 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -2501,7 +2538,8 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -2554,7 +2592,8 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -2611,7 +2650,8 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -2720,7 +2760,8 @@ func TestOpenAPIApplication_unpackSpace(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -2802,7 +2843,8 @@ func TestOpenAPIApplication_unpackSpace(t *testing.T) { return "workspace1" case "span3": return "workspace2" - } } + } + } return "" }).AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) @@ -2909,7 +2951,8 @@ func TestOpenAPIApplication_AllowByKey(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -2952,7 +2995,8 @@ func TestOpenAPIApplication_AllowByKey(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -2995,7 +3039,8 @@ func TestOpenAPIApplication_AllowByKey(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -3037,7 +3082,8 @@ func TestOpenAPIApplication_AllowByKey(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -3080,7 +3126,8 @@ func TestOpenAPIApplication_AllowByKey(t *testing.T) { case "span1": case "span2": case "span3": - return "workspace2" } + return "workspace2" + } } return "" }).AnyTimes() @@ -3131,4 +3178,4 @@ func TestOpenAPIApplication_AllowByKey(t *testing.T) { assert.Equal(t, tt.want, got) }) } -} \ No newline at end of file +} diff --git a/backend/modules/observability/infra/config/trace.go b/backend/modules/observability/infra/config/trace.go index 18f22c036..9d8cd8ed0 100644 --- a/backend/modules/observability/infra/config/trace.go +++ b/backend/modules/observability/infra/config/trace.go @@ -6,6 +6,7 @@ package config import ( "context" "fmt" + "github.com/coze-dev/coze-loop/backend/modules/observability/domain/component/config" "github.com/coze-dev/coze-loop/backend/pkg/conf" "github.com/coze-dev/coze-loop/backend/pkg/logs" From 974fd53c1b0e29bb0c9a4d012ee1c2c7ecaac64d Mon Sep 17 00:00:00 2001 From: cuichen Date: Tue, 9 Sep 2025 10:56:47 +0800 Subject: [PATCH 15/29] fix Golang CI Lint --- backend/modules/observability/application/openapi.go | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/modules/observability/application/openapi.go b/backend/modules/observability/application/openapi.go index 931c64547..788cb0dfe 100644 --- a/backend/modules/observability/application/openapi.go +++ b/backend/modules/observability/application/openapi.go @@ -9,7 +9,6 @@ import ( "context" "errors" "fmt" - "io" "strconv" "strings" From 57a4458e921b1b9436c2f30c182d0ce635714739 Mon Sep 17 00:00:00 2001 From: cuichen Date: Tue, 9 Sep 2025 11:35:30 +0800 Subject: [PATCH 16/29] fix: [Coda] update openapi_test.go to use unified EmitTraceOapi method Co-Authored-By: Coda --- .../domain/component/metrics/metrics.go | 4 +-- .../domain/component/metrics/mocks/metrics.go | 36 ++++--------------- 2 files changed, 7 insertions(+), 33 deletions(-) diff --git a/backend/modules/observability/domain/component/metrics/metrics.go b/backend/modules/observability/domain/component/metrics/metrics.go index 186f12242..1ebde31f7 100644 --- a/backend/modules/observability/domain/component/metrics/metrics.go +++ b/backend/modules/observability/domain/component/metrics/metrics.go @@ -9,7 +9,5 @@ import "time" type ITraceMetrics interface { EmitListSpans(workspaceId int64, spanType string, start time.Time, isError bool) EmitGetTrace(workspaceId int64, start time.Time, isError bool) - EmitListSpansOapi(workspaceId int64, platformType, spanType string, spanSize int64, errorCode int, start time.Time, isError bool) - EmitSearchTraceOapi(workspaceId int64, platformType string, spanSize int64, errorCode int, start time.Time, isError bool) - EmitListTracesOapi(workspaceId int64, errorCode int, start time.Time, isError bool) + EmitTraceOapi(method string, workspaceId int64, platformType, spanType string, spanSize int64, errorCode int, start time.Time, isError bool) } diff --git a/backend/modules/observability/domain/component/metrics/mocks/metrics.go b/backend/modules/observability/domain/component/metrics/mocks/metrics.go index 1010b7ac3..32c1630cb 100644 --- a/backend/modules/observability/domain/component/metrics/mocks/metrics.go +++ b/backend/modules/observability/domain/component/metrics/mocks/metrics.go @@ -64,38 +64,14 @@ func (mr *MockITraceMetricsMockRecorder) EmitListSpans(workspaceId, spanType, st return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EmitListSpans", reflect.TypeOf((*MockITraceMetrics)(nil).EmitListSpans), workspaceId, spanType, start, isError) } -// EmitListSpansOapi mocks base method. -func (m *MockITraceMetrics) EmitListSpansOapi(workspaceId int64, platformType, spanType string, spanSize int64, errorCode int, start time.Time, isError bool) { +// EmitTraceOapi mocks base method. +func (m *MockITraceMetrics) EmitTraceOapi(method string, workspaceId int64, platformType, spanType string, spanSize int64, errorCode int, start time.Time, isError bool) { m.ctrl.T.Helper() - m.ctrl.Call(m, "EmitListSpansOapi", workspaceId, platformType, spanType, spanSize, errorCode, start, isError) + m.ctrl.Call(m, "EmitTraceOapi", method, workspaceId, platformType, spanType, spanSize, errorCode, start, isError) } -// EmitListSpansOapi indicates an expected call of EmitListSpansOapi. -func (mr *MockITraceMetricsMockRecorder) EmitListSpansOapi(workspaceId, platformType, spanType, spanSize, errorCode, start, isError any) *gomock.Call { +// EmitTraceOapi indicates an expected call of EmitTraceOapi. +func (mr *MockITraceMetricsMockRecorder) EmitTraceOapi(method, workspaceId, platformType, spanType, spanSize, errorCode, start, isError any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EmitListSpansOapi", reflect.TypeOf((*MockITraceMetrics)(nil).EmitListSpansOapi), workspaceId, platformType, spanType, spanSize, errorCode, start, isError) -} - -// EmitListTracesOapi mocks base method. -func (m *MockITraceMetrics) EmitListTracesOapi(workspaceId int64, errorCode int, start time.Time, isError bool) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "EmitListTracesOapi", workspaceId, errorCode, start, isError) -} - -// EmitListTracesOapi indicates an expected call of EmitListTracesOapi. -func (mr *MockITraceMetricsMockRecorder) EmitListTracesOapi(workspaceId, errorCode, start, isError any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EmitListTracesOapi", reflect.TypeOf((*MockITraceMetrics)(nil).EmitListTracesOapi), workspaceId, errorCode, start, isError) -} - -// EmitSearchTraceOapi mocks base method. -func (m *MockITraceMetrics) EmitSearchTraceOapi(workspaceId int64, platformType string, spanSize int64, errorCode int, start time.Time, isError bool) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "EmitSearchTraceOapi", workspaceId, platformType, spanSize, errorCode, start, isError) -} - -// EmitSearchTraceOapi indicates an expected call of EmitSearchTraceOapi. -func (mr *MockITraceMetricsMockRecorder) EmitSearchTraceOapi(workspaceId, platformType, spanSize, errorCode, start, isError any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EmitSearchTraceOapi", reflect.TypeOf((*MockITraceMetrics)(nil).EmitSearchTraceOapi), workspaceId, platformType, spanSize, errorCode, start, isError) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EmitTraceOapi", reflect.TypeOf((*MockITraceMetrics)(nil).EmitTraceOapi), method, workspaceId, platformType, spanType, spanSize, errorCode, start, isError) } From 50f2210bc150bd9b8800ac011be80abc86d921f2 Mon Sep 17 00:00:00 2001 From: cuichen Date: Tue, 9 Sep 2025 11:38:30 +0800 Subject: [PATCH 17/29] trace openapi metrc --- .../observability/application/openapi.go | 6 +- .../observability/application/openapi_test.go | 81 ++++++++++++++----- .../observability/infra/metrics/metrics.go | 29 +++---- 3 files changed, 81 insertions(+), 35 deletions(-) diff --git a/backend/modules/observability/application/openapi.go b/backend/modules/observability/application/openapi.go index 788cb0dfe..1a9cee02f 100644 --- a/backend/modules/observability/application/openapi.go +++ b/backend/modules/observability/application/openapi.go @@ -464,7 +464,7 @@ func (o *OpenAPIApplication) SearchTraceOApi(ctx context.Context, req *openapi.S errCode := 0 defer func() { if req != nil { - o.metrics.EmitSearchTraceOapi(req.WorkspaceID, req.GetPlatformType(), int64(spansSize), errCode, st, err != nil) + o.metrics.EmitTraceOapi("SearchTraceOApi", req.WorkspaceID, req.GetPlatformType(), "", int64(spansSize), errCode, st, err != nil) } }() @@ -566,7 +566,7 @@ func (o *OpenAPIApplication) ListSpansOApi(ctx context.Context, req *openapi.Lis resp := openapi.NewListSpansOApiResponse() defer func() { if req != nil { - o.metrics.EmitListSpansOapi(req.WorkspaceID, req.GetPlatformType(), req.GetSpanListType(), int64(spansSize), errCode, st, err != nil) + o.metrics.EmitTraceOapi("ListSpansOApi", req.WorkspaceID, req.GetPlatformType(), req.GetSpanListType(), int64(spansSize), errCode, st, err != nil) } }() if err = o.validateListSpansOApi(ctx, req); err != nil { @@ -678,7 +678,7 @@ func (o *OpenAPIApplication) ListTracesOApi(ctx context.Context, req *openapi.Li st := time.Now() errCode := 0 defer func() { - o.metrics.EmitListTracesOapi(req.WorkspaceID, errCode, st, err != nil) + o.metrics.EmitTraceOapi("ListTracesOApi", req.WorkspaceID, "", "", 0, errCode, st, err != nil) }() if err = o.validateListTracesOApiReq(ctx, req); err != nil { diff --git a/backend/modules/observability/application/openapi_test.go b/backend/modules/observability/application/openapi_test.go index 2b53b878d..d447f689c 100644 --- a/backend/modules/observability/application/openapi_test.go +++ b/backend/modules/observability/application/openapi_test.go @@ -1495,7 +1495,8 @@ func TestOpenAPIApplication_ListSpansOApi(t *testing.T) { rateLimiterMock.EXPECT().NewRateLimiter().Return(rateLimiterFactoryMock).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - metricsMock.EXPECT().EmitListSpansOapi( + metricsMock.EXPECT().EmitTraceOapi( + "ListSpansOApi", int64(123), gomock.Any(), gomock.Any(), @@ -1559,7 +1560,8 @@ func TestOpenAPIApplication_ListSpansOApi(t *testing.T) { rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - metricsMock.EXPECT().EmitListSpansOapi( + metricsMock.EXPECT().EmitTraceOapi( + "ListSpansOApi", int64(123), gomock.Any(), gomock.Any(), @@ -1616,7 +1618,8 @@ func TestOpenAPIApplication_ListSpansOApi(t *testing.T) { rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - metricsMock.EXPECT().EmitListSpansOapi( + metricsMock.EXPECT().EmitTraceOapi( + "ListSpansOApi", int64(123), gomock.Any(), gomock.Any(), @@ -1675,7 +1678,8 @@ func TestOpenAPIApplication_ListSpansOApi(t *testing.T) { } return "" }).AnyTimes() - metricsMock.EXPECT().EmitListSpansOapi( + metricsMock.EXPECT().EmitTraceOapi( + "ListSpansOApi", int64(123), gomock.Any(), gomock.Any(), @@ -1736,7 +1740,8 @@ func TestOpenAPIApplication_ListSpansOApi(t *testing.T) { } return "" }).AnyTimes() - metricsMock.EXPECT().EmitListSpansOapi( + metricsMock.EXPECT().EmitTraceOapi( + "ListSpansOApi", int64(123), gomock.Any(), gomock.Any(), @@ -1852,9 +1857,11 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { } return "" }).AnyTimes() - metricsMock.EXPECT().EmitSearchTraceOapi( + metricsMock.EXPECT().EmitTraceOapi( + "SearchTraceOApi", int64(123), gomock.Any(), + "", gomock.Any(), gomock.Any(), gomock.Any(), @@ -1920,9 +1927,11 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { } return "" }).AnyTimes() - metricsMock.EXPECT().EmitSearchTraceOapi( + metricsMock.EXPECT().EmitTraceOapi( + "SearchTraceOApi", int64(123), gomock.Any(), + "", gomock.Any(), gomock.Any(), gomock.Any(), @@ -2022,9 +2031,11 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - metricsMock.EXPECT().EmitSearchTraceOapi( + metricsMock.EXPECT().EmitTraceOapi( + "SearchTraceOApi", int64(123), gomock.Any(), + "", gomock.Any(), gomock.Any(), gomock.Any(), @@ -2077,9 +2088,11 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - metricsMock.EXPECT().EmitSearchTraceOapi( + metricsMock.EXPECT().EmitTraceOapi( + "SearchTraceOApi", int64(123), gomock.Any(), + "", gomock.Any(), gomock.Any(), gomock.Any(), @@ -2134,9 +2147,11 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - metricsMock.EXPECT().EmitSearchTraceOapi( + metricsMock.EXPECT().EmitTraceOapi( + "SearchTraceOApi", int64(123), gomock.Any(), + "", gomock.Any(), gomock.Any(), gomock.Any(), @@ -2196,9 +2211,11 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { } return "" }).AnyTimes() - metricsMock.EXPECT().EmitSearchTraceOapi( + metricsMock.EXPECT().EmitTraceOapi( + "SearchTraceOApi", int64(123), gomock.Any(), + "", gomock.Any(), gomock.Any(), gomock.Any(), @@ -2321,8 +2338,12 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { rateLimiterMock.EXPECT().NewRateLimiter().Return(rateLimiterFactoryMock).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - metricsMock.EXPECT().EmitListTracesOapi( + metricsMock.EXPECT().EmitTraceOapi( + "ListTracesOApi", int64(123), + "", + "", + int64(0), gomock.Any(), gomock.Any(), gomock.Any(), @@ -2387,7 +2408,11 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - metricsMock.EXPECT().EmitListTracesOapi( + metricsMock.EXPECT().EmitTraceOapi( + "ListTracesOApi", + int64(0), + "", + "", int64(0), gomock.Any(), gomock.Any(), @@ -2440,8 +2465,12 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - metricsMock.EXPECT().EmitListTracesOapi( + metricsMock.EXPECT().EmitTraceOapi( + "ListTracesOApi", int64(123), + "", + "", + int64(0), gomock.Any(), gomock.Any(), gomock.Any(), @@ -2493,8 +2522,12 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - metricsMock.EXPECT().EmitListTracesOapi( + metricsMock.EXPECT().EmitTraceOapi( + "ListTracesOApi", int64(123), + "", + "", + int64(0), gomock.Any(), gomock.Any(), gomock.Any(), @@ -2547,8 +2580,12 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - metricsMock.EXPECT().EmitListTracesOapi( + metricsMock.EXPECT().EmitTraceOapi( + "ListTracesOApi", int64(123), + "", + "", + int64(0), gomock.Any(), gomock.Any(), gomock.Any(), @@ -2602,8 +2639,12 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { rateLimiterMock.EXPECT().NewRateLimiter().Return(rateLimiterFactoryMock).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - metricsMock.EXPECT().EmitListTracesOapi( + metricsMock.EXPECT().EmitTraceOapi( + "ListTracesOApi", int64(123), + "", + "", + int64(0), gomock.Any(), gomock.Any(), gomock.Any(), @@ -2660,8 +2701,12 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { rateLimiterMock.EXPECT().NewRateLimiter().Return(rateLimiterFactoryMock).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - metricsMock.EXPECT().EmitListTracesOapi( + metricsMock.EXPECT().EmitTraceOapi( + "ListTracesOApi", int64(123), + "", + "", + int64(0), gomock.Any(), gomock.Any(), gomock.Any(), diff --git a/backend/modules/observability/infra/metrics/metrics.go b/backend/modules/observability/infra/metrics/metrics.go index 5091d24ee..419c5aa44 100644 --- a/backend/modules/observability/infra/metrics/metrics.go +++ b/backend/modules/observability/infra/metrics/metrics.go @@ -16,11 +16,9 @@ import ( const ( traceSpansMetricsName = "trace_spans" - getTraceSuffix = "get_trace" - listSpansSuffix = "list_spans" - searchTraceOApiSuffix = "search_trace_oapi" - listSpansOApiSuffix = "list_spans_oapi" - listTracesOApiSuffix = "list_traces_oapi" + getTraceSuffix = "get_trace" + listSpansSuffix = "list_spans" + traceOApiSuffix = "trace_oapi" throughputSuffix = ".throughput" latencySuffix = ".latency" @@ -28,6 +26,7 @@ const ( ) const ( + tagMethod = "method" tagSpaceID = "workspace_id" tagPlatformType = "platform_type" tagSpanType = "span_type" @@ -37,6 +36,7 @@ const ( func traceQueryTagNames() []string { return []string{ + tagMethod, tagSpaceID, tagPlatformType, tagSpanType, @@ -102,21 +102,22 @@ func (t *TraceMetricsImpl) EmitGetTrace(workspaceId int64, start time.Time, isEr metrics.Timer(time.Since(start).Microseconds(), metrics.WithSuffix(getTraceSuffix+latencySuffix))) } -func (t *TraceMetricsImpl) EmitListSpansOapi(workspaceId int64, platformType, spanType string, spanSize int64, errorCode int, start time.Time, isError bool) { +func (t *TraceMetricsImpl) EmitTraceOapi(method string, workspaceId int64, platformType, spanType string, spanSize int64, errorCode int, start time.Time, isError bool) { if t.spansMetrics == nil { return } t.spansMetrics.Emit( []metrics.T{ + {Name: tagMethod, Value: method}, {Name: tagSpaceID, Value: strconv.FormatInt(workspaceId, 10)}, {Name: tagIsErr, Value: strconv.FormatBool(isError)}, {Name: tagPlatformType, Value: platformType}, {Name: tagSpanType, Value: spanType}, {Name: tagErrCode, Value: strconv.Itoa(errorCode)}, }, - metrics.Counter(1, metrics.WithSuffix(listSpansOApiSuffix+throughputSuffix)), - metrics.Counter(spanSize, metrics.WithSuffix(listSpansOApiSuffix+sizeSuffix)), - metrics.Timer(time.Since(start).Microseconds(), metrics.WithSuffix(listSpansOApiSuffix+latencySuffix))) + metrics.Counter(1, metrics.WithSuffix(traceOApiSuffix+throughputSuffix)), + metrics.Counter(spanSize, metrics.WithSuffix(traceOApiSuffix+sizeSuffix)), + metrics.Timer(time.Since(start).Microseconds(), metrics.WithSuffix(traceOApiSuffix+latencySuffix))) } func (t *TraceMetricsImpl) EmitSearchTraceOapi(workspaceId int64, platformType string, spanSize int64, errorCode int, start time.Time, isError bool) { @@ -130,9 +131,9 @@ func (t *TraceMetricsImpl) EmitSearchTraceOapi(workspaceId int64, platformType s {Name: tagIsErr, Value: strconv.FormatBool(isError)}, {Name: tagErrCode, Value: strconv.Itoa(errorCode)}, }, - metrics.Counter(1, metrics.WithSuffix(searchTraceOApiSuffix+throughputSuffix)), - metrics.Counter(spanSize, metrics.WithSuffix(searchTraceOApiSuffix+sizeSuffix)), - metrics.Timer(time.Since(start).Microseconds(), metrics.WithSuffix(searchTraceOApiSuffix+latencySuffix))) + metrics.Counter(1, metrics.WithSuffix(traceOApiSuffix+throughputSuffix)), + metrics.Counter(spanSize, metrics.WithSuffix(traceOApiSuffix+sizeSuffix)), + metrics.Timer(time.Since(start).Microseconds(), metrics.WithSuffix(traceOApiSuffix+latencySuffix))) } func (t *TraceMetricsImpl) EmitListTracesOapi(workspaceId int64, errorCode int, start time.Time, isError bool) { @@ -145,6 +146,6 @@ func (t *TraceMetricsImpl) EmitListTracesOapi(workspaceId int64, errorCode int, {Name: tagIsErr, Value: strconv.FormatBool(isError)}, {Name: tagErrCode, Value: strconv.Itoa(errorCode)}, }, - metrics.Counter(1, metrics.WithSuffix(listTracesOApiSuffix+throughputSuffix)), - metrics.Timer(time.Since(start).Microseconds(), metrics.WithSuffix(listTracesOApiSuffix+latencySuffix))) + metrics.Counter(1, metrics.WithSuffix(traceOApiSuffix+throughputSuffix)), + metrics.Timer(time.Since(start).Microseconds(), metrics.WithSuffix(traceOApiSuffix+latencySuffix))) } From bfa3dde0bcb7d31760e368351ee550e8b0563cf9 Mon Sep 17 00:00:00 2001 From: cuichen Date: Tue, 9 Sep 2025 12:02:01 +0800 Subject: [PATCH 18/29] trace openapi metric --- .../observability/infra/metrics/metrics.go | 30 ---- .../infra/metrics/metrics_test.go | 143 +----------------- 2 files changed, 5 insertions(+), 168 deletions(-) diff --git a/backend/modules/observability/infra/metrics/metrics.go b/backend/modules/observability/infra/metrics/metrics.go index 419c5aa44..1f8d790a9 100644 --- a/backend/modules/observability/infra/metrics/metrics.go +++ b/backend/modules/observability/infra/metrics/metrics.go @@ -119,33 +119,3 @@ func (t *TraceMetricsImpl) EmitTraceOapi(method string, workspaceId int64, platf metrics.Counter(spanSize, metrics.WithSuffix(traceOApiSuffix+sizeSuffix)), metrics.Timer(time.Since(start).Microseconds(), metrics.WithSuffix(traceOApiSuffix+latencySuffix))) } - -func (t *TraceMetricsImpl) EmitSearchTraceOapi(workspaceId int64, platformType string, spanSize int64, errorCode int, start time.Time, isError bool) { - if t.spansMetrics == nil { - return - } - t.spansMetrics.Emit( - []metrics.T{ - {Name: tagSpaceID, Value: strconv.FormatInt(workspaceId, 10)}, - {Name: tagPlatformType, Value: platformType}, - {Name: tagIsErr, Value: strconv.FormatBool(isError)}, - {Name: tagErrCode, Value: strconv.Itoa(errorCode)}, - }, - metrics.Counter(1, metrics.WithSuffix(traceOApiSuffix+throughputSuffix)), - metrics.Counter(spanSize, metrics.WithSuffix(traceOApiSuffix+sizeSuffix)), - metrics.Timer(time.Since(start).Microseconds(), metrics.WithSuffix(traceOApiSuffix+latencySuffix))) -} - -func (t *TraceMetricsImpl) EmitListTracesOapi(workspaceId int64, errorCode int, start time.Time, isError bool) { - if t.spansMetrics == nil { - return - } - t.spansMetrics.Emit( - []metrics.T{ - {Name: tagSpaceID, Value: strconv.FormatInt(workspaceId, 10)}, - {Name: tagIsErr, Value: strconv.FormatBool(isError)}, - {Name: tagErrCode, Value: strconv.Itoa(errorCode)}, - }, - metrics.Counter(1, metrics.WithSuffix(traceOApiSuffix+throughputSuffix)), - metrics.Timer(time.Since(start).Microseconds(), metrics.WithSuffix(traceOApiSuffix+latencySuffix))) -} diff --git a/backend/modules/observability/infra/metrics/metrics_test.go b/backend/modules/observability/infra/metrics/metrics_test.go index f939139fc..fefb25592 100644 --- a/backend/modules/observability/infra/metrics/metrics_test.go +++ b/backend/modules/observability/infra/metrics/metrics_test.go @@ -199,6 +199,7 @@ func TestTraceMetricsImpl_EmitListSpansOapi(t *testing.T) { spansMetrics infraMetrics.Metric } type args struct { + method string workspaceId int64 platformType string spanType string @@ -219,7 +220,7 @@ func TestTraceMetricsImpl_EmitListSpansOapi(t *testing.T) { spansMetrics: nil, } }, - args: args{123, "coze", "llm", 1024, 0, time.Now(), false}, + args: args{"1", 123, "coze", "llm", 1024, 0, time.Now(), false}, }, { name: "should emit metrics when spansMetrics is not nil", @@ -230,7 +231,7 @@ func TestTraceMetricsImpl_EmitListSpansOapi(t *testing.T) { spansMetrics: m, } }, - args: args{123, "coze", "llm", 1024, 0, time.Now(), false}, + args: args{"1", 123, "coze", "llm", 1024, 0, time.Now(), false}, }, { name: "should emit metrics with error", @@ -241,7 +242,7 @@ func TestTraceMetricsImpl_EmitListSpansOapi(t *testing.T) { spansMetrics: m, } }, - args: args{456, "openai", "chat", 2048, 500, time.Now(), true}, + args: args{"1", 456, "openai", "chat", 2048, 500, time.Now(), true}, }, } for _, tt := range tests { @@ -257,141 +258,7 @@ func TestTraceMetricsImpl_EmitListSpansOapi(t *testing.T) { spansMetrics: fields.spansMetrics, } assert.NotPanics(t, func() { - tr.EmitListSpansOapi(tt.args.workspaceId, tt.args.platformType, tt.args.spanType, tt.args.spanSize, tt.args.errorCode, tt.args.start, tt.args.isError) - }) - }) - } -} - -func TestTraceMetricsImpl_EmitSearchTraceOapi(t *testing.T) { - type fields struct { - spansMetrics infraMetrics.Metric - } - type args struct { - workspaceId int64 - platformType string - spanSize int64 - errorCode int - start time.Time - isError bool - } - tests := []struct { - name string - fieldsGetter func(ctrl *gomock.Controller) fields - args args - }{ - { - name: "should not panic when spansMetrics is nil", - fieldsGetter: func(ctrl *gomock.Controller) fields { - return fields{ - spansMetrics: nil, - } - }, - args: args{123, "coze", 512, 0, time.Now(), false}, - }, - { - name: "should emit metrics when spansMetrics is not nil", - fieldsGetter: func(ctrl *gomock.Controller) fields { - m := mocks.NewMockMetric(ctrl) - m.EXPECT().Emit(gomock.Any(), gomock.Any()).Times(1) - return fields{ - spansMetrics: m, - } - }, - args: args{123, "coze", 512, 0, time.Now(), false}, - }, - { - name: "should emit metrics with error", - fieldsGetter: func(ctrl *gomock.Controller) fields { - m := mocks.NewMockMetric(ctrl) - m.EXPECT().Emit(gomock.Any(), gomock.Any()).Times(1) - return fields{ - spansMetrics: m, - } - }, - args: args{789, "openai", 1024, 400, time.Now(), true}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - t.Cleanup(func() { - singletonTraceMetrics = nil - traceMetricsOnce = sync.Once{} - }) - ctrl := gomock.NewController(t) - defer ctrl.Finish() - fields := tt.fieldsGetter(ctrl) - tr := &TraceMetricsImpl{ - spansMetrics: fields.spansMetrics, - } - assert.NotPanics(t, func() { - tr.EmitSearchTraceOapi(tt.args.workspaceId, tt.args.platformType, tt.args.spanSize, tt.args.errorCode, tt.args.start, tt.args.isError) - }) - }) - } -} - -func TestTraceMetricsImpl_EmitListTracesOapi(t *testing.T) { - type fields struct { - spansMetrics infraMetrics.Metric - } - type args struct { - workspaceId int64 - errorCode int - start time.Time - isError bool - } - tests := []struct { - name string - fieldsGetter func(ctrl *gomock.Controller) fields - args args - }{ - { - name: "should not panic when spansMetrics is nil", - fieldsGetter: func(ctrl *gomock.Controller) fields { - return fields{ - spansMetrics: nil, - } - }, - args: args{123, 0, time.Now(), false}, - }, - { - name: "should emit metrics when spansMetrics is not nil", - fieldsGetter: func(ctrl *gomock.Controller) fields { - m := mocks.NewMockMetric(ctrl) - m.EXPECT().Emit(gomock.Any(), gomock.Any()).Times(1) - return fields{ - spansMetrics: m, - } - }, - args: args{123, 0, time.Now(), false}, - }, - { - name: "should emit metrics with error", - fieldsGetter: func(ctrl *gomock.Controller) fields { - m := mocks.NewMockMetric(ctrl) - m.EXPECT().Emit(gomock.Any(), gomock.Any()).Times(1) - return fields{ - spansMetrics: m, - } - }, - args: args{456, 404, time.Now(), true}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - t.Cleanup(func() { - singletonTraceMetrics = nil - traceMetricsOnce = sync.Once{} - }) - ctrl := gomock.NewController(t) - defer ctrl.Finish() - fields := tt.fieldsGetter(ctrl) - tr := &TraceMetricsImpl{ - spansMetrics: fields.spansMetrics, - } - assert.NotPanics(t, func() { - tr.EmitListTracesOapi(tt.args.workspaceId, tt.args.errorCode, tt.args.start, tt.args.isError) + tr.EmitTraceOapi(tt.args.method, tt.args.workspaceId, tt.args.platformType, tt.args.spanType, tt.args.spanSize, tt.args.errorCode, tt.args.start, tt.args.isError) }) }) } From 8fcf33922b4d8bd3d043420ad83f168d43981001 Mon Sep 17 00:00:00 2001 From: cuichen Date: Tue, 9 Sep 2025 14:00:47 +0800 Subject: [PATCH 19/29] trace openapi metric --- backend/modules/observability/infra/metrics/metrics_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/modules/observability/infra/metrics/metrics_test.go b/backend/modules/observability/infra/metrics/metrics_test.go index fefb25592..9ea40e666 100644 --- a/backend/modules/observability/infra/metrics/metrics_test.go +++ b/backend/modules/observability/infra/metrics/metrics_test.go @@ -266,6 +266,7 @@ func TestTraceMetricsImpl_EmitListSpansOapi(t *testing.T) { func TestTraceQueryTagNames(t *testing.T) { expected := []string{ + tagMethod, tagSpaceID, tagPlatformType, tagSpanType, @@ -274,5 +275,5 @@ func TestTraceQueryTagNames(t *testing.T) { } result := traceQueryTagNames() assert.Equal(t, expected, result) - assert.Len(t, result, 5) + assert.Len(t, result, 6) } From 5e81c4abb34de1e8e594d22fb243f66f5c2b0d6c Mon Sep 17 00:00:00 2001 From: cuichen Date: Tue, 9 Sep 2025 15:03:20 +0800 Subject: [PATCH 20/29] =?UTF-8?q?test:=20[Coda]=20=E8=A1=A5=E5=85=85openap?= =?UTF-8?q?i=5Ftest.go=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B=EF=BC=8C?= =?UTF-8?q?=E6=8F=90=E5=8D=87=E8=A6=86=E7=9B=96=E7=8E=87=E8=87=B371.6%?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Coda --- .../observability/application/openapi_test.go | 668 +++++++++++++----- 1 file changed, 492 insertions(+), 176 deletions(-) diff --git a/backend/modules/observability/application/openapi_test.go b/backend/modules/observability/application/openapi_test.go index d447f689c..57fd18a65 100644 --- a/backend/modules/observability/application/openapi_test.go +++ b/backend/modules/observability/application/openapi_test.go @@ -7,7 +7,6 @@ import ( "bytes" "compress/gzip" "context" - "strconv" "testing" "time" @@ -2769,7 +2768,55 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { } // TestOpenAPIApplication_unpackSpace tests the unpackSpace method -func TestOpenAPIApplication_unpackSpace(t *testing.T) { + +// TestOpenAPIApplication_AllowByKey tests the AllowByKey method + +// TestNewOpenAPIApplication 测试构造函数 +func TestNewOpenAPIApplication(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + traceServiceMock := servicemocks.NewMockITraceService(ctrl) + authMock := rpcmocks.NewMockIAuthProvider(ctrl) + benefitMock := benefitmocks.NewMockIBenefitService(ctrl) + tenantMock := tenantmocks.NewMockITenantProvider(ctrl) + workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + rateLimiterFactoryMock := limitermocks.NewMockIRateLimiterFactory(ctrl) + rateLimiterMock := limitermocks.NewMockIRateLimiter(ctrl) + traceConfigMock := configmocks.NewMockITraceConfig(ctrl) + metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) + + rateLimiterFactoryMock.EXPECT().NewRateLimiter().Return(rateLimiterMock) + + app, err := NewOpenAPIApplication( + traceServiceMock, + authMock, + benefitMock, + tenantMock, + workspaceMock, + rateLimiterFactoryMock, + traceConfigMock, + metricsMock, + ) + + assert.NoError(t, err) + assert.NotNil(t, app) + + // 验证返回的实例类型 + openAPIApp, ok := app.(*OpenAPIApplication) + assert.True(t, ok) + assert.NotNil(t, openAPIApp.traceService) + assert.NotNil(t, openAPIApp.auth) + assert.NotNil(t, openAPIApp.benefit) + assert.NotNil(t, openAPIApp.tenant) + assert.NotNil(t, openAPIApp.workspace) + assert.NotNil(t, openAPIApp.rateLimiter) + assert.NotNil(t, openAPIApp.traceConfig) + assert.NotNil(t, openAPIApp.metrics) +} + +// 补充IngestTraces的边界测试场景 +func TestOpenAPIApplication_IngestTraces_AdditionalScenarios(t *testing.T) { type fields struct { traceService service.ITraceService auth rpc.IAuthProvider @@ -2781,35 +2828,26 @@ func TestOpenAPIApplication_unpackSpace(t *testing.T) { metrics metrics.ITraceMetrics } type args struct { - ctx context.Context - spans []*span.InputSpan + ctx context.Context + req *openapi.IngestTracesRequest } tests := []struct { name string fieldsGetter func(ctrl *gomock.Controller) fields args args - want map[string][]*span.InputSpan + want *openapi.IngestTracesResponse + wantErr bool }{ { - name: "nil spans", + name: "permission check fails", fieldsGetter: func(ctrl *gomock.Controller) fields { traceServiceMock := servicemocks.NewMockITraceService(ctrl) authMock := rpcmocks.NewMockIAuthProvider(ctrl) + authMock.EXPECT().CheckIngestPermission(gomock.Any(), gomock.Any()).Return(assert.AnError) benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() - workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { - if len(spans) > 0 { - switch spans[0].SpanID { - case "span1": - case "span2": - case "span3": - return "workspace2" - } - } - return "" - }).AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("1").AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -2826,27 +2864,33 @@ func TestOpenAPIApplication_unpackSpace(t *testing.T) { } }, args: args{ - ctx: context.Background(), - spans: nil, + ctx: context.Background(), + req: &openapi.IngestTracesRequest{ + Spans: []*span.InputSpan{ + { + WorkspaceID: "1", + }, + }, + }, }, - want: nil, + want: nil, + wantErr: true, }, { - name: "empty workspace ID skipped", + name: "benefit check fails - insufficient capacity", fieldsGetter: func(ctrl *gomock.Controller) fields { traceServiceMock := servicemocks.NewMockITraceService(ctrl) authMock := rpcmocks.NewMockIAuthProvider(ctrl) + authMock.EXPECT().CheckIngestPermission(gomock.Any(), gomock.Any()).Return(nil) benefitMock := benefitmocks.NewMockIBenefitService(ctrl) + benefitMock.EXPECT().CheckTraceBenefit(gomock.Any(), gomock.Any()).Return(&benefit.CheckTraceBenefitResult{ + AccountAvailable: true, + IsEnough: false, + StorageDuration: 3, + }, nil) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() - workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { - if len(spans) > 0 { - switch spans[0].SpanID { - } - } - return "" - }).AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("1").AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -2864,34 +2908,32 @@ func TestOpenAPIApplication_unpackSpace(t *testing.T) { }, args: args{ ctx: context.Background(), - spans: []*span.InputSpan{ - {SpanID: "span1"}, + req: &openapi.IngestTracesRequest{ + Spans: []*span.InputSpan{ + { + WorkspaceID: "1", + }, + }, }, }, - want: map[string][]*span.InputSpan{}, + want: nil, + wantErr: true, }, { - name: "spans grouped by workspace ID", + name: "benefit check fails - account not available", fieldsGetter: func(ctrl *gomock.Controller) fields { traceServiceMock := servicemocks.NewMockITraceService(ctrl) authMock := rpcmocks.NewMockIAuthProvider(ctrl) + authMock.EXPECT().CheckIngestPermission(gomock.Any(), gomock.Any()).Return(nil) benefitMock := benefitmocks.NewMockIBenefitService(ctrl) + benefitMock.EXPECT().CheckTraceBenefit(gomock.Any(), gomock.Any()).Return(&benefit.CheckTraceBenefitResult{ + AccountAvailable: false, + IsEnough: true, + StorageDuration: 3, + }, nil) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() - workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { - if len(spans) > 0 { - switch spans[0].SpanID { - case "span1": - return "workspace1" - case "span2": - return "workspace1" - case "span3": - return "workspace2" - } - } - return "" - }).AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("1").AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) @@ -2909,24 +2951,86 @@ func TestOpenAPIApplication_unpackSpace(t *testing.T) { }, args: args{ ctx: context.Background(), - spans: []*span.InputSpan{ - {SpanID: "span1"}, - {SpanID: "span2"}, - {SpanID: "span3"}, + req: &openapi.IngestTracesRequest{ + Spans: []*span.InputSpan{ + { + WorkspaceID: "1", + }, + }, }, }, - want: map[string][]*span.InputSpan{ - "workspace1": { - {SpanID: "span1", WorkspaceID: "workspace1"}, - {SpanID: "span2", WorkspaceID: "workspace1"}, - }, - "workspace2": { - {SpanID: "span3", WorkspaceID: "workspace2"}, + want: nil, + wantErr: true, + }, + { + name: "invalid workspace id format", + fieldsGetter: func(ctrl *gomock.Controller) fields { + traceServiceMock := servicemocks.NewMockITraceService(ctrl) + authMock := rpcmocks.NewMockIAuthProvider(ctrl) + authMock.EXPECT().CheckIngestPermission(gomock.Any(), gomock.Any()).Return(nil) + benefitMock := benefitmocks.NewMockIBenefitService(ctrl) + tenantMock := tenantmocks.NewMockITenantProvider(ctrl) + workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("invalid").AnyTimes() + rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) + rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() + traceConfigMock := configmocks.NewMockITraceConfig(ctrl) + metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) + return fields{ + traceService: traceServiceMock, + auth: authMock, + benefit: benefitMock, + tenant: tenantMock, + workspace: workspaceMock, + rateLimiter: rateLimiterMock, + traceConfig: traceConfigMock, + metrics: metricsMock, + } + }, + args: args{ + ctx: context.Background(), + req: &openapi.IngestTracesRequest{ + Spans: []*span.InputSpan{ + { + WorkspaceID: "1", + }, + }, }, }, + want: nil, + wantErr: true, + }, + { + name: "nil request", + fieldsGetter: func(ctrl *gomock.Controller) fields { + traceServiceMock := servicemocks.NewMockITraceService(ctrl) + authMock := rpcmocks.NewMockIAuthProvider(ctrl) + benefitMock := benefitmocks.NewMockIBenefitService(ctrl) + tenantMock := tenantmocks.NewMockITenantProvider(ctrl) + workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) + rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() + traceConfigMock := configmocks.NewMockITraceConfig(ctrl) + metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) + return fields{ + traceService: traceServiceMock, + auth: authMock, + benefit: benefitMock, + tenant: tenantMock, + workspace: workspaceMock, + rateLimiter: rateLimiterMock, + traceConfig: traceConfigMock, + metrics: metricsMock, + } + }, + args: args{ + ctx: context.Background(), + req: nil, + }, + want: nil, + wantErr: true, }, } - for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctrl := gomock.NewController(t) @@ -2942,25 +3046,15 @@ func TestOpenAPIApplication_unpackSpace(t *testing.T) { traceConfig: fields.traceConfig, metrics: fields.metrics, } - err := error(nil) - assert.NoError(t, err) - got := o.unpackSpace(tt.args.ctx, tt.args.spans) - if tt.want == nil { - assert.Nil(t, got) - } else { - assert.Equal(t, len(tt.want), len(got)) - for workspaceID, expectedSpans := range tt.want { - actualSpans, exists := got[workspaceID] - assert.True(t, exists) - assert.Equal(t, len(expectedSpans), len(actualSpans)) - } - } + got, err := o.IngestTraces(tt.args.ctx, tt.args.req) + assert.Equal(t, tt.wantErr, err != nil) + assert.Equal(t, tt.want, got) }) } } -// TestOpenAPIApplication_AllowByKey tests the AllowByKey method -func TestOpenAPIApplication_AllowByKey(t *testing.T) { +// 补充CreateAnnotation的更多测试场景 +func TestOpenAPIApplication_CreateAnnotation_AdditionalScenarios(t *testing.T) { type fields struct { traceService service.ITraceService auth rpc.IAuthProvider @@ -2972,42 +3066,75 @@ func TestOpenAPIApplication_AllowByKey(t *testing.T) { metrics metrics.ITraceMetrics } type args struct { - ctx context.Context - workspaceID int64 + ctx context.Context + req *openapi.CreateAnnotationRequest } tests := []struct { name string fieldsGetter func(ctrl *gomock.Controller) fields args args - want bool + want *openapi.CreateAnnotationResponse + wantErr bool }{ { - name: "rate limit allowed", + name: "create annotation with double value type", fieldsGetter: func(ctrl *gomock.Controller) fields { traceServiceMock := servicemocks.NewMockITraceService(ctrl) + traceServiceMock.EXPECT().CreateAnnotation(gomock.Any(), gomock.Any()).Return(nil) + benefitMock := benefitmocks.NewMockIBenefitService(ctrl) + benefitMock.EXPECT().CheckTraceBenefit(gomock.Any(), gomock.Any()).Return(&benefit.CheckTraceBenefitResult{ + StorageDuration: 3, + }, nil) authMock := rpcmocks.NewMockIAuthProvider(ctrl) + tenantMock := tenantmocks.NewMockITenantProvider(ctrl) + workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("").AnyTimes() + rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) + rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() + traceConfigMock := configmocks.NewMockITraceConfig(ctrl) + metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) + return fields{ + traceService: traceServiceMock, + auth: authMock, + benefit: benefitMock, + tenant: tenantMock, + workspace: workspaceMock, + rateLimiter: rateLimiterMock, + traceConfig: traceConfigMock, + metrics: metricsMock, + } + }, + args: args{ + ctx: context.Background(), + req: &openapi.CreateAnnotationRequest{ + WorkspaceID: 1, + AnnotationValueType: ptr.Of(annotation.ValueType(loop_span.AnnotationValueTypeDouble)), + AnnotationValue: "3.14", + Base: &base.Base{Caller: "test"}, + }, + }, + want: openapi.NewCreateAnnotationResponse(), + wantErr: false, + }, + { + name: "create annotation with bool value type", + fieldsGetter: func(ctrl *gomock.Controller) fields { + traceServiceMock := servicemocks.NewMockITraceService(ctrl) + traceServiceMock.EXPECT().CreateAnnotation(gomock.Any(), gomock.Any()).Return(nil) benefitMock := benefitmocks.NewMockIBenefitService(ctrl) + benefitMock.EXPECT().CheckTraceBenefit(gomock.Any(), gomock.Any()).Return(&benefit.CheckTraceBenefitResult{ + StorageDuration: 3, + }, nil) + authMock := rpcmocks.NewMockIAuthProvider(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() - workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { - if len(spans) > 0 { - switch spans[0].SpanID { - case "span1": - case "span2": - case "span3": - return "workspace2" - } - } - return "" - }).AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("").AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) - rateLimiterFactoryMock := limitermocks.NewMockIRateLimiter(ctrl) - rateLimiterMock.EXPECT().NewRateLimiter().Return(rateLimiterFactoryMock).AnyTimes() + rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(100, nil) - rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), "123", 1, gomock.Any()).Return(&limiter.Result{Allowed: true}, nil) return fields{ traceService: traceServiceMock, auth: authMock, @@ -3020,13 +3147,19 @@ func TestOpenAPIApplication_AllowByKey(t *testing.T) { } }, args: args{ - ctx: context.Background(), - workspaceID: 123, + ctx: context.Background(), + req: &openapi.CreateAnnotationRequest{ + WorkspaceID: 1, + AnnotationValueType: ptr.Of(annotation.ValueType(loop_span.AnnotationValueTypeBool)), + AnnotationValue: "true", + Base: &base.Base{Caller: "test"}, + }, }, - want: true, + want: openapi.NewCreateAnnotationResponse(), + wantErr: false, }, { - name: "rate limit exceeded", + name: "create annotation with invalid double value", fieldsGetter: func(ctrl *gomock.Controller) fields { traceServiceMock := servicemocks.NewMockITraceService(ctrl) authMock := rpcmocks.NewMockIAuthProvider(ctrl) @@ -3034,24 +3167,11 @@ func TestOpenAPIApplication_AllowByKey(t *testing.T) { tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() - workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { - if len(spans) > 0 { - switch spans[0].SpanID { - case "span1": - case "span2": - case "span3": - return "workspace2" - } - } - return "" - }).AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("").AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) - rateLimiterFactoryMock := limitermocks.NewMockIRateLimiter(ctrl) - rateLimiterMock.EXPECT().NewRateLimiter().Return(rateLimiterFactoryMock).AnyTimes() + rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(100, nil) - rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), "123", 1, gomock.Any()).Return(&limiter.Result{Allowed: false}, nil) return fields{ traceService: traceServiceMock, auth: authMock, @@ -3064,13 +3184,19 @@ func TestOpenAPIApplication_AllowByKey(t *testing.T) { } }, args: args{ - ctx: context.Background(), - workspaceID: 123, + ctx: context.Background(), + req: &openapi.CreateAnnotationRequest{ + WorkspaceID: 1, + AnnotationValueType: ptr.Of(annotation.ValueType(loop_span.AnnotationValueTypeDouble)), + AnnotationValue: "invalid", + Base: &base.Base{Caller: "test"}, + }, }, - want: false, + want: nil, + wantErr: true, }, { - name: "config error returns true", + name: "create annotation with invalid bool value", fieldsGetter: func(ctrl *gomock.Controller) fields { traceServiceMock := servicemocks.NewMockITraceService(ctrl) authMock := rpcmocks.NewMockIAuthProvider(ctrl) @@ -3078,23 +3204,11 @@ func TestOpenAPIApplication_AllowByKey(t *testing.T) { tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() - workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { - if len(spans) > 0 { - switch spans[0].SpanID { - case "span1": - case "span2": - case "span3": - return "workspace2" - } - } - return "" - }).AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("").AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) - rateLimiterFactoryMock := limitermocks.NewMockIRateLimiter(ctrl) - rateLimiterMock.EXPECT().NewRateLimiter().Return(rateLimiterFactoryMock).AnyTimes() + rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(0, assert.AnError) return fields{ traceService: traceServiceMock, auth: authMock, @@ -3107,38 +3221,32 @@ func TestOpenAPIApplication_AllowByKey(t *testing.T) { } }, args: args{ - ctx: context.Background(), - workspaceID: 123, + ctx: context.Background(), + req: &openapi.CreateAnnotationRequest{ + WorkspaceID: 1, + AnnotationValueType: ptr.Of(annotation.ValueType(loop_span.AnnotationValueTypeBool)), + AnnotationValue: "invalid", + Base: &base.Base{Caller: "test"}, + }, }, - want: true, + want: nil, + wantErr: true, }, { - name: "rate limiter error returns true", + name: "benefit check fails", fieldsGetter: func(ctrl *gomock.Controller) fields { traceServiceMock := servicemocks.NewMockITraceService(ctrl) authMock := rpcmocks.NewMockIAuthProvider(ctrl) benefitMock := benefitmocks.NewMockIBenefitService(ctrl) + benefitMock.EXPECT().CheckTraceBenefit(gomock.Any(), gomock.Any()).Return(nil, assert.AnError) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() - workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { - if len(spans) > 0 { - switch spans[0].SpanID { - case "span1": - case "span2": - case "span3": - return "workspace2" - } - } - return "" - }).AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("").AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) - rateLimiterFactoryMock := limitermocks.NewMockIRateLimiter(ctrl) - rateLimiterMock.EXPECT().NewRateLimiter().Return(rateLimiterFactoryMock).AnyTimes() + rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(100, nil) - rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), "123", 1, gomock.Any()).Return(nil, assert.AnError) return fields{ traceService: traceServiceMock, auth: authMock, @@ -3151,38 +3259,35 @@ func TestOpenAPIApplication_AllowByKey(t *testing.T) { } }, args: args{ - ctx: context.Background(), - workspaceID: 123, + ctx: context.Background(), + req: &openapi.CreateAnnotationRequest{ + WorkspaceID: 1, + AnnotationValueType: ptr.Of(annotation.ValueType(loop_span.AnnotationValueTypeString)), + AnnotationValue: "test", + Base: &base.Base{Caller: "test"}, + }, }, - want: true, + want: nil, + wantErr: true, }, { - name: "nil result returns true", + name: "trace service fails", fieldsGetter: func(ctrl *gomock.Controller) fields { traceServiceMock := servicemocks.NewMockITraceService(ctrl) - authMock := rpcmocks.NewMockIAuthProvider(ctrl) + traceServiceMock.EXPECT().CreateAnnotation(gomock.Any(), gomock.Any()).Return(assert.AnError) benefitMock := benefitmocks.NewMockIBenefitService(ctrl) + benefitMock.EXPECT().CheckTraceBenefit(gomock.Any(), gomock.Any()).Return(&benefit.CheckTraceBenefitResult{ + StorageDuration: 3, + }, nil) + authMock := rpcmocks.NewMockIAuthProvider(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() - workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { - if len(spans) > 0 { - switch spans[0].SpanID { - case "span1": - case "span2": - case "span3": - return "workspace2" - } - } - return "" - }).AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("").AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) - rateLimiterFactoryMock := limitermocks.NewMockIRateLimiter(ctrl) - rateLimiterMock.EXPECT().NewRateLimiter().Return(rateLimiterFactoryMock).AnyTimes() + rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) - traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(100, nil) - rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), "123", 1, gomock.Any()).Return(nil, nil) return fields{ traceService: traceServiceMock, auth: authMock, @@ -3195,13 +3300,139 @@ func TestOpenAPIApplication_AllowByKey(t *testing.T) { } }, args: args{ - ctx: context.Background(), - workspaceID: 123, + ctx: context.Background(), + req: &openapi.CreateAnnotationRequest{ + WorkspaceID: 1, + AnnotationValueType: ptr.Of(annotation.ValueType(loop_span.AnnotationValueTypeString)), + AnnotationValue: "test", + Base: &base.Base{Caller: "test"}, + }, }, - want: true, + want: nil, + wantErr: true, }, } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + fields := tt.fieldsGetter(ctrl) + o := &OpenAPIApplication{ + traceService: fields.traceService, + auth: fields.auth, + benefit: fields.benefit, + tenant: fields.tenant, + workspace: fields.workspace, + rateLimiter: fields.rateLimiter.NewRateLimiter(), + traceConfig: fields.traceConfig, + metrics: fields.metrics, + } + got, err := o.CreateAnnotation(tt.args.ctx, tt.args.req) + assert.Equal(t, tt.wantErr, err != nil) + assert.Equal(t, tt.want, got) + }) + } +} +// 补充DeleteAnnotation的更多测试场景 +func TestOpenAPIApplication_DeleteAnnotation_AdditionalScenarios(t *testing.T) { + type fields struct { + traceService service.ITraceService + auth rpc.IAuthProvider + benefit benefit.IBenefitService + tenant tenant.ITenantProvider + workspace workspace.IWorkSpaceProvider + rateLimiter limiter.IRateLimiterFactory + traceConfig config.ITraceConfig + metrics metrics.ITraceMetrics + } + type args struct { + ctx context.Context + req *openapi.DeleteAnnotationRequest + } + tests := []struct { + name string + fieldsGetter func(ctrl *gomock.Controller) fields + args args + want *openapi.DeleteAnnotationResponse + wantErr bool + }{ + { + name: "benefit check fails", + fieldsGetter: func(ctrl *gomock.Controller) fields { + traceServiceMock := servicemocks.NewMockITraceService(ctrl) + authMock := rpcmocks.NewMockIAuthProvider(ctrl) + benefitMock := benefitmocks.NewMockIBenefitService(ctrl) + benefitMock.EXPECT().CheckTraceBenefit(gomock.Any(), gomock.Any()).Return(nil, assert.AnError) + tenantMock := tenantmocks.NewMockITenantProvider(ctrl) + workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("").AnyTimes() + rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) + rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() + traceConfigMock := configmocks.NewMockITraceConfig(ctrl) + metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) + return fields{ + traceService: traceServiceMock, + auth: authMock, + benefit: benefitMock, + tenant: tenantMock, + workspace: workspaceMock, + rateLimiter: rateLimiterMock, + traceConfig: traceConfigMock, + metrics: metricsMock, + } + }, + args: args{ + ctx: context.Background(), + req: &openapi.DeleteAnnotationRequest{ + WorkspaceID: 1, + Base: &base.Base{Caller: "test"}, + }, + }, + want: nil, + wantErr: true, + }, + { + name: "trace service fails", + fieldsGetter: func(ctrl *gomock.Controller) fields { + traceServiceMock := servicemocks.NewMockITraceService(ctrl) + traceServiceMock.EXPECT().DeleteAnnotation(gomock.Any(), gomock.Any()).Return(assert.AnError) + benefitMock := benefitmocks.NewMockIBenefitService(ctrl) + benefitMock.EXPECT().CheckTraceBenefit(gomock.Any(), gomock.Any()).Return(&benefit.CheckTraceBenefitResult{ + StorageDuration: 3, + }, nil) + authMock := rpcmocks.NewMockIAuthProvider(ctrl) + tenantMock := tenantmocks.NewMockITenantProvider(ctrl) + workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("").AnyTimes() + rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) + rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() + traceConfigMock := configmocks.NewMockITraceConfig(ctrl) + metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) + return fields{ + traceService: traceServiceMock, + auth: authMock, + benefit: benefitMock, + tenant: tenantMock, + workspace: workspaceMock, + rateLimiter: rateLimiterMock, + traceConfig: traceConfigMock, + metrics: metricsMock, + } + }, + args: args{ + ctx: context.Background(), + req: &openapi.DeleteAnnotationRequest{ + WorkspaceID: 1, + Base: &base.Base{Caller: "test"}, + }, + }, + want: nil, + wantErr: true, + }, + } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctrl := gomock.NewController(t) @@ -3217,10 +3448,95 @@ func TestOpenAPIApplication_AllowByKey(t *testing.T) { traceConfig: fields.traceConfig, metrics: fields.metrics, } - err := error(nil) - assert.NoError(t, err) - got := o.AllowByKey(tt.args.ctx, strconv.FormatInt(tt.args.workspaceID, 10)) + got, err := o.DeleteAnnotation(tt.args.ctx, tt.args.req) + assert.Equal(t, tt.wantErr, err != nil) assert.Equal(t, tt.want, got) }) } } + +// 测试validate和build函数 +func TestOpenAPIApplication_validateIngestTracesReq(t *testing.T) { + app := &OpenAPIApplication{} + + // 测试nil请求 + err := app.validateIngestTracesReq(context.Background(), nil) + assert.Error(t, err) + + // 测试空spans + err = app.validateIngestTracesReq(context.Background(), &openapi.IngestTracesRequest{ + Spans: []*span.InputSpan{}, + }) + assert.Error(t, err) + + // 测试不同workspace id的spans + err = app.validateIngestTracesReq(context.Background(), &openapi.IngestTracesRequest{ + Spans: []*span.InputSpan{ + {WorkspaceID: "1"}, + {WorkspaceID: "2"}, + }, + }) + assert.Error(t, err) + + // 测试正常情况 + err = app.validateIngestTracesReq(context.Background(), &openapi.IngestTracesRequest{ + Spans: []*span.InputSpan{ + {WorkspaceID: "1"}, + {WorkspaceID: "1"}, + }, + }) + assert.NoError(t, err) +} + +func TestOpenAPIApplication_validateIngestTracesReqByTenant(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + traceConfigMock := configmocks.NewMockITraceConfig(ctrl) + app := &OpenAPIApplication{ + traceConfig: traceConfigMock, + } + + // 测试nil请求 + traceConfigMock.EXPECT().GetTraceIngestTenantProducerCfg(gomock.Any()).Return(nil, nil) + err := app.validateIngestTracesReqByTenant(context.Background(), "tenant", nil) + assert.Error(t, err) + + // 测试超过最大span长度 + traceConfigMock.EXPECT().GetTraceIngestTenantProducerCfg(gomock.Any()).Return(map[string]*config.IngestConfig{ + "tenant": {MaxSpanLength: 1}, + }, nil) + err = app.validateIngestTracesReqByTenant(context.Background(), "tenant", &openapi.IngestTracesRequest{ + Spans: []*span.InputSpan{{}, {}}, + }) + assert.Error(t, err) + + // 测试正常情况 + traceConfigMock.EXPECT().GetTraceIngestTenantProducerCfg(gomock.Any()).Return(nil, nil) + err = app.validateIngestTracesReqByTenant(context.Background(), "tenant", &openapi.IngestTracesRequest{ + Spans: []*span.InputSpan{{}}, + }) + assert.NoError(t, err) +} + + +func TestOpenAPIApplication_unpackTenant(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + tenantMock := tenantmocks.NewMockITenantProvider(ctrl) + app := &OpenAPIApplication{ + tenant: tenantMock, + } + + // 测试nil spans + result := app.unpackTenant(context.Background(), nil) + assert.Nil(t, result) + + // 测试正常情况 + tenantMock.EXPECT().GetIngestTenant(gomock.Any(), gomock.Any()).Return("tenant1") + result = app.unpackTenant(context.Background(), []*loop_span.Span{{SpanID: "test"}}) + assert.Len(t, result, 1) + assert.Len(t, result["tenant1"], 1) +} + From 45d4f1acdd879fadd38cd265bb22c0558c223e55 Mon Sep 17 00:00:00 2001 From: cuichen Date: Tue, 9 Sep 2025 17:26:00 +0800 Subject: [PATCH 21/29] test: [Coda] add comprehensive unit tests for observability infra components with 100% coverage Co-Authored-By: Coda --- .../observability/infra/config/trace_test.go | 964 ++++++++++++++++++ .../observability/infra/rpc/auth/auth_test.go | 587 +++++++++++ .../rpc/auth/mocks/authservice_client_mock.go | 63 ++ .../infra/workspace/workspace_test.go | 197 ++++ 4 files changed, 1811 insertions(+) create mode 100755 backend/modules/observability/infra/config/trace_test.go create mode 100755 backend/modules/observability/infra/rpc/auth/auth_test.go create mode 100644 backend/modules/observability/infra/rpc/auth/mocks/authservice_client_mock.go create mode 100755 backend/modules/observability/infra/workspace/workspace_test.go diff --git a/backend/modules/observability/infra/config/trace_test.go b/backend/modules/observability/infra/config/trace_test.go new file mode 100755 index 000000000..2ad255c1b --- /dev/null +++ b/backend/modules/observability/infra/config/trace_test.go @@ -0,0 +1,964 @@ +// Copyright (c) 2025 coze-dev Authors +// SPDX-License-Identifier: Apache-2.0 + +package config + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "go.uber.org/mock/gomock" + + "github.com/coze-dev/coze-loop/backend/modules/observability/domain/component/config" + "github.com/coze-dev/coze-loop/backend/modules/observability/domain/trace/entity/loop_span" + confmocks "github.com/coze-dev/coze-loop/backend/pkg/conf/mocks" +) + +func TestTraceConfigCenter_GetSystemViews(t *testing.T) { + type fields struct { + configLoader *confmocks.MockIConfigLoader + } + type args struct { + ctx context.Context + } + tests := []struct { + name string + fieldsGetter func(ctrl *gomock.Controller) fields + args args + want []*config.SystemView + wantErr bool + }{ + { + name: "get system views successfully", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(gomock.Any(), systemViewsCfgKey, gomock.Any()). + DoAndReturn(func(ctx context.Context, key string, v interface{}, opts ...interface{}) error { + views := v.(*[]*config.SystemView) + *views = []*config.SystemView{ + {ID: 1, ViewName: "View 1"}, + {ID: 2, ViewName: "View 2"}, + } + return nil + }) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background()}, + want: []*config.SystemView{ + {ID: 1, ViewName: "View 1"}, + {ID: 2, ViewName: "View 2"}, + }, + wantErr: false, + }, + { + name: "unmarshal key failed", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(gomock.Any(), systemViewsCfgKey, gomock.Any()). + Return(fmt.Errorf("unmarshal error")) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background()}, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + f := tt.fieldsGetter(ctrl) + tr := &TraceConfigCenter{ + IConfigLoader: f.configLoader, + } + got, err := tr.GetSystemViews(tt.args.ctx) + assert.Equal(t, tt.wantErr, err != nil) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestTraceConfigCenter_GetPlatformTenants(t *testing.T) { + type fields struct { + configLoader *confmocks.MockIConfigLoader + } + type args struct { + ctx context.Context + } + tests := []struct { + name string + fieldsGetter func(ctrl *gomock.Controller) fields + args args + want *config.PlatformTenantsCfg + wantErr bool + }{ + { + name: "get platform tenants successfully", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(gomock.Any(), platformTenantCfgKey, gomock.Any()). + DoAndReturn(func(ctx context.Context, key string, v interface{}, opts ...interface{}) error { + cfg := v.(*config.PlatformTenantsCfg) + cfg.Config = map[string][]string{"platform1": {"tenant1"}} + return nil + }) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background()}, + want: &config.PlatformTenantsCfg{ + Config: map[string][]string{"platform1": {"tenant1"}}, + }, + wantErr: false, + }, + { + name: "unmarshal key failed", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(gomock.Any(), platformTenantCfgKey, gomock.Any()). + Return(fmt.Errorf("unmarshal error")) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background()}, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + f := tt.fieldsGetter(ctrl) + tr := &TraceConfigCenter{ + IConfigLoader: f.configLoader, + } + got, err := tr.GetPlatformTenants(tt.args.ctx) + assert.Equal(t, tt.wantErr, err != nil) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestTraceConfigCenter_GetPlatformSpansTrans(t *testing.T) { + type fields struct { + configLoader *confmocks.MockIConfigLoader + } + type args struct { + ctx context.Context + } + tests := []struct { + name string + fieldsGetter func(ctrl *gomock.Controller) fields + args args + want *config.SpanTransHandlerConfig + wantErr bool + }{ + { + name: "get platform spans trans successfully", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(gomock.Any(), platformSpanHandlerCfgKey, gomock.Any()). + DoAndReturn(func(ctx context.Context, key string, v interface{}, opts ...interface{}) error { + cfg := v.(*config.SpanTransHandlerConfig) + cfg.PlatformCfg = make(map[string]loop_span.SpanTransCfgList) + return nil + }) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background()}, + want: &config.SpanTransHandlerConfig{ + PlatformCfg: make(map[string]loop_span.SpanTransCfgList), + }, + wantErr: false, + }, + { + name: "unmarshal key failed", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(gomock.Any(), platformSpanHandlerCfgKey, gomock.Any()). + Return(fmt.Errorf("unmarshal error")) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background()}, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + f := tt.fieldsGetter(ctrl) + tr := &TraceConfigCenter{ + IConfigLoader: f.configLoader, + } + got, err := tr.GetPlatformSpansTrans(tt.args.ctx) + assert.Equal(t, tt.wantErr, err != nil) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestTraceConfigCenter_GetTraceIngestTenantProducerCfg(t *testing.T) { + type fields struct { + configLoader *confmocks.MockIConfigLoader + } + type args struct { + ctx context.Context + } + tests := []struct { + name string + fieldsGetter func(ctrl *gomock.Controller) fields + args args + want map[string]*config.IngestConfig + wantErr bool + }{ + { + name: "get trace ingest tenant producer cfg successfully", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(context.Background(), traceIngestTenantCfgKey, gomock.Any()). + DoAndReturn(func(ctx context.Context, key string, v interface{}, opts ...interface{}) error { + cfg := v.(*map[string]*config.IngestConfig) + (*cfg)["tenant1"] = &config.IngestConfig{ + MaxSpanLength: 1000, + MqProducer: config.MqProducerCfg{Topic: "topic1"}, + } + return nil + }) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background()}, + want: map[string]*config.IngestConfig{ + "tenant1": { + MaxSpanLength: 1000, + MqProducer: config.MqProducerCfg{Topic: "topic1"}, + }, + }, + wantErr: false, + }, + { + name: "unmarshal key failed", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(context.Background(), traceIngestTenantCfgKey, gomock.Any()). + Return(fmt.Errorf("unmarshal error")) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background()}, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + f := tt.fieldsGetter(ctrl) + tr := &TraceConfigCenter{ + IConfigLoader: f.configLoader, + } + got, err := tr.GetTraceIngestTenantProducerCfg(tt.args.ctx) + assert.Equal(t, tt.wantErr, err != nil) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestTraceConfigCenter_GetAnnotationMqProducerCfg(t *testing.T) { + type fields struct { + configLoader *confmocks.MockIConfigLoader + } + type args struct { + ctx context.Context + } + tests := []struct { + name string + fieldsGetter func(ctrl *gomock.Controller) fields + args args + want *config.MqProducerCfg + wantErr bool + }{ + { + name: "get annotation mq producer cfg successfully", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(context.Background(), annotationMqProducerCfgKey, gomock.Any()). + DoAndReturn(func(ctx context.Context, key string, v interface{}, opts ...interface{}) error { + cfg := v.(*config.MqProducerCfg) + cfg.Topic = "annotation_topic" + return nil + }) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background()}, + want: &config.MqProducerCfg{ + Topic: "annotation_topic", + }, + wantErr: false, + }, + { + name: "unmarshal key failed", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(context.Background(), annotationMqProducerCfgKey, gomock.Any()). + Return(fmt.Errorf("unmarshal error")) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background()}, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + f := tt.fieldsGetter(ctrl) + tr := &TraceConfigCenter{ + IConfigLoader: f.configLoader, + } + got, err := tr.GetAnnotationMqProducerCfg(tt.args.ctx) + assert.Equal(t, tt.wantErr, err != nil) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestTraceConfigCenter_GetTraceCkCfg(t *testing.T) { + type fields struct { + configLoader *confmocks.MockIConfigLoader + } + type args struct { + ctx context.Context + } + tests := []struct { + name string + fieldsGetter func(ctrl *gomock.Controller) fields + args args + want *config.TraceCKCfg + wantErr bool + }{ + { + name: "get trace ck cfg successfully", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(context.Background(), traceCkCfgKey, gomock.Any()). + DoAndReturn(func(ctx context.Context, key string, v interface{}, opts ...interface{}) error { + cfg := v.(*config.TraceCKCfg) + cfg.DataBase = "trace_db" + return nil + }) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background()}, + want: &config.TraceCKCfg{ + DataBase: "trace_db", + }, + wantErr: false, + }, + { + name: "unmarshal key failed", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(context.Background(), traceCkCfgKey, gomock.Any()). + Return(fmt.Errorf("unmarshal error")) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background()}, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + f := tt.fieldsGetter(ctrl) + tr := &TraceConfigCenter{ + IConfigLoader: f.configLoader, + } + got, err := tr.GetTraceCkCfg(tt.args.ctx) + assert.Equal(t, tt.wantErr, err != nil) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestTraceConfigCenter_GetTenantConfig(t *testing.T) { + type fields struct { + configLoader *confmocks.MockIConfigLoader + } + type args struct { + ctx context.Context + } + tests := []struct { + name string + fieldsGetter func(ctrl *gomock.Controller) fields + args args + want *config.TenantCfg + wantErr bool + }{ + { + name: "get tenant config successfully", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(gomock.Any(), tenantTablesCfgKey, gomock.Any()). + DoAndReturn(func(ctx context.Context, key string, v interface{}, opts ...interface{}) error { + cfg := v.(**config.TenantCfg) + *cfg = &config.TenantCfg{ + DefaultIngestTenant: "default_tenant", + } + return nil + }) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background()}, + want: &config.TenantCfg{ + DefaultIngestTenant: "default_tenant", + }, + wantErr: false, + }, + { + name: "unmarshal key failed", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(gomock.Any(), tenantTablesCfgKey, gomock.Any()). + Return(fmt.Errorf("unmarshal error")) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background()}, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + f := tt.fieldsGetter(ctrl) + tr := &TraceConfigCenter{ + IConfigLoader: f.configLoader, + } + got, err := tr.GetTenantConfig(tt.args.ctx) + assert.Equal(t, tt.wantErr, err != nil) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestTraceConfigCenter_GetTraceFieldMetaInfo(t *testing.T) { + type fields struct { + configLoader *confmocks.MockIConfigLoader + } + type args struct { + ctx context.Context + } + tests := []struct { + name string + fieldsGetter func(ctrl *gomock.Controller) fields + args args + want *config.TraceFieldMetaInfoCfg + wantErr bool + }{ + { + name: "get trace field meta info successfully", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(gomock.Any(), traceFieldMetaInfoCfgKey, gomock.Any()). + DoAndReturn(func(ctx context.Context, key string, v interface{}, opts ...interface{}) error { + cfg := v.(**config.TraceFieldMetaInfoCfg) + *cfg = &config.TraceFieldMetaInfoCfg{ + AvailableFields: map[string]*config.FieldMeta{"field1": {}}, + } + return nil + }) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background()}, + want: &config.TraceFieldMetaInfoCfg{ + AvailableFields: map[string]*config.FieldMeta{"field1": {}}, + }, + wantErr: false, + }, + { + name: "unmarshal key failed", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(gomock.Any(), traceFieldMetaInfoCfgKey, gomock.Any()). + Return(fmt.Errorf("unmarshal error")) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background()}, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + f := tt.fieldsGetter(ctrl) + tr := &TraceConfigCenter{ + IConfigLoader: f.configLoader, + } + got, err := tr.GetTraceFieldMetaInfo(tt.args.ctx) + assert.Equal(t, tt.wantErr, err != nil) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestTraceConfigCenter_GetTraceDataMaxDurationDay(t *testing.T) { + type fields struct { + configLoader *confmocks.MockIConfigLoader + } + type args struct { + ctx context.Context + platformPtr *string + } + tests := []struct { + name string + fieldsGetter func(ctrl *gomock.Controller) fields + args args + want int64 + }{ + { + name: "platform ptr is nil, return default duration", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background(), platformPtr: nil}, + want: 7, + }, + { + name: "get duration successfully with platform type", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(gomock.Any(), traceMaxDurationDay, gomock.Any()). + DoAndReturn(func(ctx context.Context, key string, v interface{}, opts ...interface{}) error { + mp := v.(*map[string]int64) + (*mp)["coze"] = 30 + return nil + }) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background(), platformPtr: stringPtr("coze")}, + want: 30, + }, + { + name: "platform type not found, return default duration", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(gomock.Any(), traceMaxDurationDay, gomock.Any()). + DoAndReturn(func(ctx context.Context, key string, v interface{}, opts ...interface{}) error { + mp := v.(*map[string]int64) + (*mp)["other"] = 15 + return nil + }) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background(), platformPtr: stringPtr("coze")}, + want: 7, + }, + { + name: "platform type has zero value, return default duration", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(gomock.Any(), traceMaxDurationDay, gomock.Any()). + DoAndReturn(func(ctx context.Context, key string, v interface{}, opts ...interface{}) error { + mp := v.(*map[string]int64) + (*mp)["coze"] = 0 + return nil + }) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background(), platformPtr: stringPtr("coze")}, + want: 7, + }, + { + name: "unmarshal key failed, return default duration", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(gomock.Any(), traceMaxDurationDay, gomock.Any()). + Return(fmt.Errorf("unmarshal error")) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background(), platformPtr: stringPtr("coze")}, + want: 7, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + f := tt.fieldsGetter(ctrl) + tr := &TraceConfigCenter{ + IConfigLoader: f.configLoader, + } + got := tr.GetTraceDataMaxDurationDay(tt.args.ctx, tt.args.platformPtr) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestTraceConfigCenter_GetDefaultTraceTenant(t *testing.T) { + type fields struct { + configLoader *confmocks.MockIConfigLoader + traceDefaultTenant string + } + type args struct { + ctx context.Context + } + tests := []struct { + name string + fieldsGetter func(ctrl *gomock.Controller) fields + args args + want string + }{ + { + name: "get default trace tenant successfully", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + return fields{ + configLoader: mockLoader, + traceDefaultTenant: "default_tenant", + } + }, + args: args{ctx: context.Background()}, + want: "default_tenant", + }, + { + name: "get empty default trace tenant", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + return fields{ + configLoader: mockLoader, + traceDefaultTenant: "", + } + }, + args: args{ctx: context.Background()}, + want: "", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + f := tt.fieldsGetter(ctrl) + tr := &TraceConfigCenter{ + IConfigLoader: f.configLoader, + traceDefaultTenant: f.traceDefaultTenant, + } + got := tr.GetDefaultTraceTenant(tt.args.ctx) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestTraceConfigCenter_getDefaultTraceTenant(t *testing.T) { + type fields struct { + configLoader *confmocks.MockIConfigLoader + traceDefaultTenant string + } + type args struct { + ctx context.Context + } + tests := []struct { + name string + fieldsGetter func(ctrl *gomock.Controller) fields + args args + want string + wantErr bool + }{ + { + name: "trace default tenant already set", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + return fields{ + configLoader: mockLoader, + traceDefaultTenant: "existing_tenant", + } + }, + args: args{ctx: context.Background()}, + want: "existing_tenant", + wantErr: false, + }, + { + name: "get tenant config successfully", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(gomock.Any(), tenantTablesCfgKey, gomock.Any()). + DoAndReturn(func(ctx context.Context, key string, v interface{}, opts ...interface{}) error { + cfg := v.(**config.TenantCfg) + *cfg = &config.TenantCfg{ + DefaultIngestTenant: "new_tenant", + } + return nil + }) + return fields{ + configLoader: mockLoader, + traceDefaultTenant: "", + } + }, + args: args{ctx: context.Background()}, + want: "new_tenant", + wantErr: false, + }, + { + name: "get tenant config failed", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(gomock.Any(), tenantTablesCfgKey, gomock.Any()). + Return(fmt.Errorf("config error")) + return fields{ + configLoader: mockLoader, + traceDefaultTenant: "", + } + }, + args: args{ctx: context.Background()}, + want: "", + wantErr: true, + }, + { + name: "default ingest tenant is empty", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(gomock.Any(), tenantTablesCfgKey, gomock.Any()). + DoAndReturn(func(ctx context.Context, key string, v interface{}, opts ...interface{}) error { + cfg := v.(**config.TenantCfg) + *cfg = &config.TenantCfg{ + DefaultIngestTenant: "", + } + return nil + }) + return fields{ + configLoader: mockLoader, + traceDefaultTenant: "", + } + }, + args: args{ctx: context.Background()}, + want: "", + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + f := tt.fieldsGetter(ctrl) + tr := &TraceConfigCenter{ + IConfigLoader: f.configLoader, + traceDefaultTenant: f.traceDefaultTenant, + } + got, err := tr.getDefaultTraceTenant(tt.args.ctx) + assert.Equal(t, tt.wantErr, err != nil) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestTraceConfigCenter_GetAnnotationSourceCfg(t *testing.T) { + type fields struct { + configLoader *confmocks.MockIConfigLoader + } + type args struct { + ctx context.Context + } + tests := []struct { + name string + fieldsGetter func(ctrl *gomock.Controller) fields + args args + want *config.AnnotationSourceConfig + wantErr bool + }{ + { + name: "get annotation source cfg successfully", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(gomock.Any(), annotationSourceCfgKey, gomock.Any()). + DoAndReturn(func(ctx context.Context, key string, v interface{}, opts ...interface{}) error { + cfg := v.(**config.AnnotationSourceConfig) + *cfg = &config.AnnotationSourceConfig{ + SourceCfg: map[string]config.AnnotationConfig{"source1": {}}, + } + return nil + }) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background()}, + want: &config.AnnotationSourceConfig{ + SourceCfg: map[string]config.AnnotationConfig{"source1": {}}, + }, + wantErr: false, + }, + { + name: "unmarshal key failed", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(gomock.Any(), annotationSourceCfgKey, gomock.Any()). + Return(fmt.Errorf("unmarshal error")) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background()}, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + f := tt.fieldsGetter(ctrl) + tr := &TraceConfigCenter{ + IConfigLoader: f.configLoader, + } + got, err := tr.GetAnnotationSourceCfg(tt.args.ctx) + assert.Equal(t, tt.wantErr, err != nil) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestTraceConfigCenter_GetQueryMaxQPS(t *testing.T) { + type fields struct { + configLoader *confmocks.MockIConfigLoader + } + type args struct { + ctx context.Context + key string + } + tests := []struct { + name string + fieldsGetter func(ctrl *gomock.Controller) fields + args args + want int + wantErr bool + }{ + { + name: "get query max qps successfully with specific key", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(gomock.Any(), queryTraceRateLimitCfgKey, gomock.Any()). + DoAndReturn(func(ctx context.Context, key string, v interface{}, opts ...interface{}) error { + cfg := v.(**config.QueryTraceRateLimitConfig) + *cfg = &config.QueryTraceRateLimitConfig{ + SpaceMaxQPS: map[string]int{"space1": 100}, + DefaultMaxQPS: 50, + } + return nil + }) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background(), key: "space1"}, + want: 100, + wantErr: false, + }, + { + name: "get query max qps with default value", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(gomock.Any(), queryTraceRateLimitCfgKey, gomock.Any()). + DoAndReturn(func(ctx context.Context, key string, v interface{}, opts ...interface{}) error { + cfg := v.(**config.QueryTraceRateLimitConfig) + *cfg = &config.QueryTraceRateLimitConfig{ + SpaceMaxQPS: map[string]int{"space1": 100}, + DefaultMaxQPS: 50, + } + return nil + }) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background(), key: "space2"}, + want: 50, + wantErr: false, + }, + { + name: "unmarshal key failed", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(gomock.Any(), queryTraceRateLimitCfgKey, gomock.Any()). + Return(fmt.Errorf("unmarshal error")) + return fields{configLoader: mockLoader} + }, + args: args{ctx: context.Background(), key: "space1"}, + want: 0, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + f := tt.fieldsGetter(ctrl) + tr := &TraceConfigCenter{ + IConfigLoader: f.configLoader, + } + got, err := tr.GetQueryMaxQPS(tt.args.ctx, tt.args.key) + assert.Equal(t, tt.wantErr, err != nil) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestNewTraceConfigCenter(t *testing.T) { + type args struct { + confP *confmocks.MockIConfigLoader + } + tests := []struct { + name string + fieldsGetter func(ctrl *gomock.Controller) args + wantPanic bool + }{ + { + name: "create trace config center successfully", + fieldsGetter: func(ctrl *gomock.Controller) args { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(context.Background(), tenantTablesCfgKey, gomock.Any()). + DoAndReturn(func(ctx context.Context, key string, v interface{}, opts ...interface{}) error { + cfg := v.(**config.TenantCfg) + *cfg = &config.TenantCfg{ + DefaultIngestTenant: "test_tenant", + } + return nil + }) + return args{confP: mockLoader} + }, + wantPanic: false, + }, + { + name: "create trace config center with panic", + fieldsGetter: func(ctrl *gomock.Controller) args { + mockLoader := confmocks.NewMockIConfigLoader(ctrl) + mockLoader.EXPECT().UnmarshalKey(context.Background(), tenantTablesCfgKey, gomock.Any()). + Return(fmt.Errorf("config error")) + return args{confP: mockLoader} + }, + wantPanic: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + f := tt.fieldsGetter(ctrl) + + if tt.wantPanic { + assert.Panics(t, func() { + NewTraceConfigCenter(f.confP) + }) + } else { + got := NewTraceConfigCenter(f.confP) + assert.NotNil(t, got) + assert.IsType(t, &TraceConfigCenter{}, got) + } + }) + } +} + +// Helper function to create string pointer +func stringPtr(s string) *string { + return &s +} \ No newline at end of file diff --git a/backend/modules/observability/infra/rpc/auth/auth_test.go b/backend/modules/observability/infra/rpc/auth/auth_test.go new file mode 100755 index 000000000..edfb8ef64 --- /dev/null +++ b/backend/modules/observability/infra/rpc/auth/auth_test.go @@ -0,0 +1,587 @@ +// Copyright (c) 2025 coze-dev Authors +// SPDX-License-Identifier: Apache-2.0 + +package auth + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "go.uber.org/mock/gomock" + + "github.com/coze-dev/coze-loop/backend/kitex_gen/base" + "github.com/coze-dev/coze-loop/backend/kitex_gen/coze/loop/foundation/auth" + authentity "github.com/coze-dev/coze-loop/backend/kitex_gen/coze/loop/foundation/domain/auth" + "github.com/coze-dev/coze-loop/backend/modules/observability/domain/component/rpc" + "github.com/coze-dev/coze-loop/backend/modules/observability/infra/rpc/auth/mocks" + "github.com/coze-dev/coze-loop/backend/pkg/lang/ptr" +) + +func TestAuthProviderImpl_CheckWorkspacePermission(t *testing.T) { + type fields struct { + cli *mocks.MockClient + } + type args struct { + ctx context.Context + action string + workspaceId string + } + tests := []struct { + name string + fieldsGetter func(ctrl *gomock.Controller) fields + args args + wantErr bool + }{ + { + name: "check workspace permission successfully", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockClient := mocks.NewMockClient(ctrl) + mockClient.EXPECT().MCheckPermission(gomock.Any(), gomock.Any(), gomock.Any()). + DoAndReturn(func(ctx context.Context, req *auth.MCheckPermissionRequest, opts ...interface{}) (*auth.MCheckPermissionResponse, error) { + return &auth.MCheckPermissionResponse{ + BaseResp: &base.BaseResp{StatusCode: 0}, + AuthRes: []*authentity.SubjectActionObjectAuthRes{ + {IsAllowed: ptr.Of(true)}, + }, + }, nil + }) + return fields{cli: mockClient} + }, + args: args{ + ctx: context.Background(), + action: "read", + workspaceId: "12345", + }, + wantErr: false, + }, + { + name: "workspace id conversion failed - non-numeric string", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockClient := mocks.NewMockClient(ctrl) + return fields{cli: mockClient} + }, + args: args{ + ctx: context.Background(), + action: "read", + workspaceId: "invalid_id", + }, + wantErr: true, + }, + { + name: "rpc call failed", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockClient := mocks.NewMockClient(ctrl) + mockClient.EXPECT().MCheckPermission(gomock.Any(), gomock.Any(), gomock.Any()). + Return(nil, fmt.Errorf("rpc error")) + return fields{cli: mockClient} + }, + args: args{ + ctx: context.Background(), + action: "read", + workspaceId: "12345", + }, + wantErr: true, + }, + { + name: "response is nil", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockClient := mocks.NewMockClient(ctrl) + mockClient.EXPECT().MCheckPermission(gomock.Any(), gomock.Any(), gomock.Any()). + Return(nil, nil) + return fields{cli: mockClient} + }, + args: args{ + ctx: context.Background(), + action: "read", + workspaceId: "12345", + }, + wantErr: true, + }, + { + name: "response status code non-zero", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockClient := mocks.NewMockClient(ctrl) + mockClient.EXPECT().MCheckPermission(gomock.Any(), gomock.Any(), gomock.Any()). + Return(&auth.MCheckPermissionResponse{ + BaseResp: &base.BaseResp{StatusCode: 500}, + }, nil) + return fields{cli: mockClient} + }, + args: args{ + ctx: context.Background(), + action: "read", + workspaceId: "12345", + }, + wantErr: true, + }, + { + name: "permission denied - IsAllowed false", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockClient := mocks.NewMockClient(ctrl) + mockClient.EXPECT().MCheckPermission(gomock.Any(), gomock.Any(), gomock.Any()). + Return(&auth.MCheckPermissionResponse{ + BaseResp: &base.BaseResp{StatusCode: 0}, + AuthRes: []*authentity.SubjectActionObjectAuthRes{ + {IsAllowed: ptr.Of(false)}, + }, + }, nil) + return fields{cli: mockClient} + }, + args: args{ + ctx: context.Background(), + action: "read", + workspaceId: "12345", + }, + wantErr: true, + }, + { + name: "response with nil base resp", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockClient := mocks.NewMockClient(ctrl) + mockClient.EXPECT().MCheckPermission(gomock.Any(), gomock.Any(), gomock.Any()). + Return(&auth.MCheckPermissionResponse{ + BaseResp: nil, + AuthRes: []*authentity.SubjectActionObjectAuthRes{ + {IsAllowed: ptr.Of(true)}, + }, + }, nil) + return fields{cli: mockClient} + }, + args: args{ + ctx: context.Background(), + action: "read", + workspaceId: "12345", + }, + wantErr: false, + }, + { + name: "auth result is nil", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockClient := mocks.NewMockClient(ctrl) + mockClient.EXPECT().MCheckPermission(gomock.Any(), gomock.Any(), gomock.Any()). + Return(&auth.MCheckPermissionResponse{ + BaseResp: &base.BaseResp{StatusCode: 0}, + AuthRes: []*authentity.SubjectActionObjectAuthRes{ + nil, + }, + }, nil) + return fields{cli: mockClient} + }, + args: args{ + ctx: context.Background(), + action: "read", + workspaceId: "12345", + }, + wantErr: false, + }, + { + name: "empty auth results", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockClient := mocks.NewMockClient(ctrl) + mockClient.EXPECT().MCheckPermission(gomock.Any(), gomock.Any(), gomock.Any()). + Return(&auth.MCheckPermissionResponse{ + BaseResp: &base.BaseResp{StatusCode: 0}, + AuthRes: []*authentity.SubjectActionObjectAuthRes{}, + }, nil) + return fields{cli: mockClient} + }, + args: args{ + ctx: context.Background(), + action: "read", + workspaceId: "12345", + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + f := tt.fieldsGetter(ctrl) + a := &AuthProviderImpl{ + cli: f.cli, + } + err := a.CheckWorkspacePermission(tt.args.ctx, tt.args.action, tt.args.workspaceId) + assert.Equal(t, tt.wantErr, err != nil) + }) + } +} + +func TestAuthProviderImpl_CheckViewPermission(t *testing.T) { + type fields struct { + cli *mocks.MockClient + } + type args struct { + ctx context.Context + action string + workspaceId string + viewId string + } + tests := []struct { + name string + fieldsGetter func(ctrl *gomock.Controller) fields + args args + wantErr bool + }{ + { + name: "check view permission successfully", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockClient := mocks.NewMockClient(ctrl) + mockClient.EXPECT().MCheckPermission(gomock.Any(), gomock.Any(), gomock.Any()). + DoAndReturn(func(ctx context.Context, req *auth.MCheckPermissionRequest, opts ...interface{}) (*auth.MCheckPermissionResponse, error) { + return &auth.MCheckPermissionResponse{ + BaseResp: &base.BaseResp{StatusCode: 0}, + AuthRes: []*authentity.SubjectActionObjectAuthRes{ + {IsAllowed: ptr.Of(true)}, + }, + }, nil + }) + return fields{cli: mockClient} + }, + args: args{ + ctx: context.Background(), + action: "read", + workspaceId: "12345", + viewId: "view123", + }, + wantErr: false, + }, + { + name: "workspace id conversion failed - non-numeric string", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockClient := mocks.NewMockClient(ctrl) + return fields{cli: mockClient} + }, + args: args{ + ctx: context.Background(), + action: "read", + workspaceId: "invalid_id", + viewId: "view123", + }, + wantErr: true, + }, + { + name: "rpc call failed", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockClient := mocks.NewMockClient(ctrl) + mockClient.EXPECT().MCheckPermission(gomock.Any(), gomock.Any(), gomock.Any()). + Return(nil, fmt.Errorf("rpc error")) + return fields{cli: mockClient} + }, + args: args{ + ctx: context.Background(), + action: "read", + workspaceId: "12345", + viewId: "view123", + }, + wantErr: true, + }, + { + name: "response is nil", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockClient := mocks.NewMockClient(ctrl) + mockClient.EXPECT().MCheckPermission(gomock.Any(), gomock.Any(), gomock.Any()). + Return(nil, nil) + return fields{cli: mockClient} + }, + args: args{ + ctx: context.Background(), + action: "read", + workspaceId: "12345", + viewId: "view123", + }, + wantErr: true, + }, + { + name: "response status code non-zero", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockClient := mocks.NewMockClient(ctrl) + mockClient.EXPECT().MCheckPermission(gomock.Any(), gomock.Any(), gomock.Any()). + Return(&auth.MCheckPermissionResponse{ + BaseResp: &base.BaseResp{StatusCode: 500}, + }, nil) + return fields{cli: mockClient} + }, + args: args{ + ctx: context.Background(), + action: "read", + workspaceId: "12345", + viewId: "view123", + }, + wantErr: true, + }, + { + name: "permission denied - IsAllowed false", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockClient := mocks.NewMockClient(ctrl) + mockClient.EXPECT().MCheckPermission(gomock.Any(), gomock.Any(), gomock.Any()). + Return(&auth.MCheckPermissionResponse{ + BaseResp: &base.BaseResp{StatusCode: 0}, + AuthRes: []*authentity.SubjectActionObjectAuthRes{ + {IsAllowed: ptr.Of(false)}, + }, + }, nil) + return fields{cli: mockClient} + }, + args: args{ + ctx: context.Background(), + action: "read", + workspaceId: "12345", + viewId: "view123", + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + f := tt.fieldsGetter(ctrl) + a := &AuthProviderImpl{ + cli: f.cli, + } + err := a.CheckViewPermission(tt.args.ctx, tt.args.action, tt.args.workspaceId, tt.args.viewId) + assert.Equal(t, tt.wantErr, err != nil) + }) + } +} + +func TestAuthProviderImpl_CheckIngestPermission(t *testing.T) { + type fields struct { + cli *mocks.MockClient + } + type args struct { + ctx context.Context + workspaceId string + } + tests := []struct { + name string + fieldsGetter func(ctrl *gomock.Controller) fields + args args + wantErr bool + }{ + { + name: "check ingest permission successfully", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockClient := mocks.NewMockClient(ctrl) + mockClient.EXPECT().MCheckPermission(gomock.Any(), gomock.Any(), gomock.Any()). + DoAndReturn(func(ctx context.Context, req *auth.MCheckPermissionRequest, opts ...interface{}) (*auth.MCheckPermissionResponse, error) { + // Verify the action is correct + assert.Equal(t, rpc.AuthActionTraceIngest, *req.Auths[0].Action) + return &auth.MCheckPermissionResponse{ + BaseResp: &base.BaseResp{StatusCode: 0}, + AuthRes: []*authentity.SubjectActionObjectAuthRes{ + {IsAllowed: ptr.Of(true)}, + }, + }, nil + }) + return fields{cli: mockClient} + }, + args: args{ + ctx: context.Background(), + workspaceId: "12345", + }, + wantErr: false, + }, + { + name: "check ingest permission failed - workspace permission check failed", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockClient := mocks.NewMockClient(ctrl) + mockClient.EXPECT().MCheckPermission(gomock.Any(), gomock.Any(), gomock.Any()). + Return(nil, fmt.Errorf("rpc error")) + return fields{cli: mockClient} + }, + args: args{ + ctx: context.Background(), + workspaceId: "12345", + }, + wantErr: true, + }, + { + name: "check ingest permission failed - invalid workspace id", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockClient := mocks.NewMockClient(ctrl) + return fields{cli: mockClient} + }, + args: args{ + ctx: context.Background(), + workspaceId: "invalid_id", + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + f := tt.fieldsGetter(ctrl) + a := &AuthProviderImpl{ + cli: f.cli, + } + err := a.CheckIngestPermission(tt.args.ctx, tt.args.workspaceId) + assert.Equal(t, tt.wantErr, err != nil) + }) + } +} + +func TestAuthProviderImpl_CheckQueryPermission(t *testing.T) { + type fields struct { + cli *mocks.MockClient + } + type args struct { + ctx context.Context + workspaceId string + platformType string + } + tests := []struct { + name string + fieldsGetter func(ctrl *gomock.Controller) fields + args args + wantErr bool + }{ + { + name: "check query permission successfully", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockClient := mocks.NewMockClient(ctrl) + mockClient.EXPECT().MCheckPermission(gomock.Any(), gomock.Any(), gomock.Any()). + DoAndReturn(func(ctx context.Context, req *auth.MCheckPermissionRequest, opts ...interface{}) (*auth.MCheckPermissionResponse, error) { + // Verify the action is correct + assert.Equal(t, rpc.AuthActionTraceList, *req.Auths[0].Action) + return &auth.MCheckPermissionResponse{ + BaseResp: &base.BaseResp{StatusCode: 0}, + AuthRes: []*authentity.SubjectActionObjectAuthRes{ + {IsAllowed: ptr.Of(true)}, + }, + }, nil + }) + return fields{cli: mockClient} + }, + args: args{ + ctx: context.Background(), + workspaceId: "12345", + platformType: "coze", + }, + wantErr: false, + }, + { + name: "check query permission failed - workspace permission check failed", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockClient := mocks.NewMockClient(ctrl) + mockClient.EXPECT().MCheckPermission(gomock.Any(), gomock.Any(), gomock.Any()). + Return(nil, fmt.Errorf("rpc error")) + return fields{cli: mockClient} + }, + args: args{ + ctx: context.Background(), + workspaceId: "12345", + platformType: "coze", + }, + wantErr: true, + }, + { + name: "check query permission failed - invalid workspace id", + fieldsGetter: func(ctrl *gomock.Controller) fields { + mockClient := mocks.NewMockClient(ctrl) + return fields{cli: mockClient} + }, + args: args{ + ctx: context.Background(), + workspaceId: "invalid_id", + platformType: "coze", + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + f := tt.fieldsGetter(ctrl) + a := &AuthProviderImpl{ + cli: f.cli, + } + err := a.CheckQueryPermission(tt.args.ctx, tt.args.workspaceId, tt.args.platformType) + assert.Equal(t, tt.wantErr, err != nil) + }) + } +} + +func TestNewAuthProvider(t *testing.T) { + type args struct { + cli *mocks.MockClient + } + tests := []struct { + name string + fieldsGetter func(ctrl *gomock.Controller) args + want rpc.IAuthProvider + }{ + { + name: "create new auth provider successfully", + fieldsGetter: func(ctrl *gomock.Controller) args { + mockClient := mocks.NewMockClient(ctrl) + return args{cli: mockClient} + }, + want: &AuthProviderImpl{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + f := tt.fieldsGetter(ctrl) + got := NewAuthProvider(f.cli) + assert.NotNil(t, got) + assert.IsType(t, &AuthProviderImpl{}, got) + }) + } +} + +func TestAuthProviderImpl_Interface(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockClient := mocks.NewMockClient(ctrl) + + // Verify that AuthProviderImpl implements IAuthProvider interface + var _ rpc.IAuthProvider = &AuthProviderImpl{} + + provider := NewAuthProvider(mockClient) + assert.NotNil(t, provider) + assert.IsType(t, &AuthProviderImpl{}, provider) +} + +func TestAuthProviderImpl_ErrorCodes(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockClient := mocks.NewMockClient(ctrl) + provider := &AuthProviderImpl{cli: mockClient} + + // Test invalid workspace ID error code + err := provider.CheckWorkspacePermission(context.Background(), "read", "invalid") + assert.NotNil(t, err) + + // Check if error is wrapped with correct error code + assert.Contains(t, err.Error(), "internal error") + assert.Contains(t, err.Error(), "internal error") + // Test RPC error code + mockClient.EXPECT().MCheckPermission(gomock.Any(), gomock.Any(), gomock.Any()). + Return(nil, fmt.Errorf("rpc error")) + + err = provider.CheckWorkspacePermission(context.Background(), "read", "12345") + assert.NotNil(t, err) + + // Test permission denied error code + mockClient.EXPECT().MCheckPermission(gomock.Any(), gomock.Any(), gomock.Any()). + Return(&auth.MCheckPermissionResponse{ + BaseResp: &base.BaseResp{StatusCode: 0}, + AuthRes: []*authentity.SubjectActionObjectAuthRes{ + {IsAllowed: ptr.Of(false)}, + }, + }, nil) + + err = provider.CheckWorkspacePermission(context.Background(), "read", "12345") + assert.NotNil(t, err) +} \ No newline at end of file diff --git a/backend/modules/observability/infra/rpc/auth/mocks/authservice_client_mock.go b/backend/modules/observability/infra/rpc/auth/mocks/authservice_client_mock.go new file mode 100644 index 000000000..70f8f15a6 --- /dev/null +++ b/backend/modules/observability/infra/rpc/auth/mocks/authservice_client_mock.go @@ -0,0 +1,63 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/coze-dev/coze-loop/backend/kitex_gen/coze/loop/foundation/auth/authservice (interfaces: Client) +// +// Generated by this command: +// +// mockgen -destination=mocks/authservice_client_mock.go -package=mocks github.com/coze-dev/coze-loop/backend/kitex_gen/coze/loop/foundation/auth/authservice Client +// + +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + reflect "reflect" + + callopt "github.com/cloudwego/kitex/client/callopt" + auth "github.com/coze-dev/coze-loop/backend/kitex_gen/coze/loop/foundation/auth" + gomock "go.uber.org/mock/gomock" +) + +// MockClient is a mock of Client interface. +type MockClient struct { + ctrl *gomock.Controller + recorder *MockClientMockRecorder + isgomock struct{} +} + +// MockClientMockRecorder is the mock recorder for MockClient. +type MockClientMockRecorder struct { + mock *MockClient +} + +// NewMockClient creates a new mock instance. +func NewMockClient(ctrl *gomock.Controller) *MockClient { + mock := &MockClient{ctrl: ctrl} + mock.recorder = &MockClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockClient) EXPECT() *MockClientMockRecorder { + return m.recorder +} + +// MCheckPermission mocks base method. +func (m *MockClient) MCheckPermission(ctx context.Context, request *auth.MCheckPermissionRequest, callOptions ...callopt.Option) (*auth.MCheckPermissionResponse, error) { + m.ctrl.T.Helper() + varargs := []any{ctx, request} + for _, a := range callOptions { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "MCheckPermission", varargs...) + ret0, _ := ret[0].(*auth.MCheckPermissionResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// MCheckPermission indicates an expected call of MCheckPermission. +func (mr *MockClientMockRecorder) MCheckPermission(ctx, request any, callOptions ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, request}, callOptions...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MCheckPermission", reflect.TypeOf((*MockClient)(nil).MCheckPermission), varargs...) +} diff --git a/backend/modules/observability/infra/workspace/workspace_test.go b/backend/modules/observability/infra/workspace/workspace_test.go new file mode 100755 index 000000000..1142431fd --- /dev/null +++ b/backend/modules/observability/infra/workspace/workspace_test.go @@ -0,0 +1,197 @@ +// Copyright (c) 2025 coze-dev Authors +// SPDX-License-Identifier: Apache-2.0 + +package workspace + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/coze-dev/coze-loop/backend/kitex_gen/coze/loop/observability/domain/span" + "github.com/coze-dev/coze-loop/backend/modules/observability/domain/component/workspace" +) + +func TestWorkspaceProviderImpl_GetIngestWorkSpaceID(t *testing.T) { + type args struct { + ctx context.Context + spans []*span.InputSpan + } + tests := []struct { + name string + args args + want string + }{ + { + name: "empty spans array, return empty string", + args: args{ + ctx: context.Background(), + spans: []*span.InputSpan{}, + }, + want: "", + }, + { + name: "nil spans, return empty string", + args: args{ + ctx: context.Background(), + spans: nil, + }, + want: "", + }, + { + name: "normal spans array, return first span workspace id", + args: args{ + ctx: context.Background(), + spans: []*span.InputSpan{ + {WorkspaceID: "workspace1"}, + {WorkspaceID: "workspace2"}, + }, + }, + want: "workspace1", + }, + { + name: "first span has empty workspace id", + args: args{ + ctx: context.Background(), + spans: []*span.InputSpan{ + {WorkspaceID: ""}, + {WorkspaceID: "workspace2"}, + }, + }, + want: "", + }, + { + name: "single span with workspace id", + args: args{ + ctx: context.Background(), + spans: []*span.InputSpan{ + {WorkspaceID: "single_workspace"}, + }, + }, + want: "single_workspace", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + w := &WorkspaceProviderImpl{} + got := w.GetIngestWorkSpaceID(tt.args.ctx, tt.args.spans) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestWorkspaceProviderImpl_GetQueryWorkSpaceID(t *testing.T) { + type args struct { + ctx context.Context + requestWorkspaceID int64 + } + tests := []struct { + name string + args args + want string + }{ + { + name: "positive workspace id conversion", + args: args{ + ctx: context.Background(), + requestWorkspaceID: 12345, + }, + want: "12345", + }, + { + name: "negative workspace id conversion", + args: args{ + ctx: context.Background(), + requestWorkspaceID: -1, + }, + want: "-1", + }, + { + name: "zero workspace id conversion", + args: args{ + ctx: context.Background(), + requestWorkspaceID: 0, + }, + want: "0", + }, + { + name: "large positive workspace id conversion", + args: args{ + ctx: context.Background(), + requestWorkspaceID: 9223372036854775807, // max int64 + }, + want: "9223372036854775807", + }, + { + name: "large negative workspace id conversion", + args: args{ + ctx: context.Background(), + requestWorkspaceID: -9223372036854775808, // min int64 + }, + want: "-9223372036854775808", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + w := &WorkspaceProviderImpl{} + got := w.GetQueryWorkSpaceID(tt.args.ctx, tt.args.requestWorkspaceID) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestNewWorkspaceProvider(t *testing.T) { + tests := []struct { + name string + want workspace.IWorkSpaceProvider + }{ + { + name: "create new workspace provider successfully", + want: &WorkspaceProviderImpl{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := NewWorkspaceProvider() + assert.NotNil(t, got) + assert.IsType(t, &WorkspaceProviderImpl{}, got) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestWorkspaceProviderImpl_Interface(t *testing.T) { + // Verify that WorkspaceProviderImpl implements IWorkSpaceProvider interface + var _ workspace.IWorkSpaceProvider = &WorkspaceProviderImpl{} + + provider := NewWorkspaceProvider() + assert.NotNil(t, provider) + + // Test interface methods exist and are callable + workspaceID := provider.GetQueryWorkSpaceID(context.Background(), 123) + assert.Equal(t, "123", workspaceID) + + spans := []*span.InputSpan{{WorkspaceID: "test"}} + ingestID := provider.GetIngestWorkSpaceID(context.Background(), spans) + assert.Equal(t, "test", ingestID) +} + +func TestWorkspaceProviderImpl_EdgeCases(t *testing.T) { + provider := &WorkspaceProviderImpl{} + + // Test with nil context (should still work) + got := provider.GetQueryWorkSpaceID(nil, 456) + assert.Equal(t, "456", got) + + // Test with nil context for GetIngestWorkSpaceID + spans := []*span.InputSpan{{WorkspaceID: "test_nil_ctx"}} + ingestID := provider.GetIngestWorkSpaceID(nil, spans) + assert.Equal(t, "test_nil_ctx", ingestID) + + // Test with nil spans element - this would cause panic in the actual code + // So we test the actual behavior which is to return empty string for empty array + emptySpans := []*span.InputSpan{} + emptyID := provider.GetIngestWorkSpaceID(context.Background(), emptySpans) + assert.Equal(t, "", emptyID) +} \ No newline at end of file From 645205a0fb38aaa3a8aae68a4eb30159b90f3a11 Mon Sep 17 00:00:00 2001 From: cuichen Date: Tue, 9 Sep 2025 17:26:41 +0800 Subject: [PATCH 22/29] trace openapi add UT --- .../observability/application/openapi_test.go | 26 +-- .../infra/metrics/metrics_test.go | 205 +++++++++++++++++- .../infra/rpc/auth/mocks/auth_client_mock.go | 10 + 3 files changed, 219 insertions(+), 22 deletions(-) create mode 100644 backend/modules/observability/infra/rpc/auth/mocks/auth_client_mock.go diff --git a/backend/modules/observability/application/openapi_test.go b/backend/modules/observability/application/openapi_test.go index 57fd18a65..bd747a7b7 100644 --- a/backend/modules/observability/application/openapi_test.go +++ b/backend/modules/observability/application/openapi_test.go @@ -2801,7 +2801,7 @@ func TestNewOpenAPIApplication(t *testing.T) { assert.NoError(t, err) assert.NotNil(t, app) - + // 验证返回的实例类型 openAPIApp, ok := app.(*OpenAPIApplication) assert.True(t, ok) @@ -3458,17 +3458,17 @@ func TestOpenAPIApplication_DeleteAnnotation_AdditionalScenarios(t *testing.T) { // 测试validate和build函数 func TestOpenAPIApplication_validateIngestTracesReq(t *testing.T) { app := &OpenAPIApplication{} - + // 测试nil请求 err := app.validateIngestTracesReq(context.Background(), nil) assert.Error(t, err) - + // 测试空spans err = app.validateIngestTracesReq(context.Background(), &openapi.IngestTracesRequest{ Spans: []*span.InputSpan{}, }) assert.Error(t, err) - + // 测试不同workspace id的spans err = app.validateIngestTracesReq(context.Background(), &openapi.IngestTracesRequest{ Spans: []*span.InputSpan{ @@ -3477,7 +3477,7 @@ func TestOpenAPIApplication_validateIngestTracesReq(t *testing.T) { }, }) assert.Error(t, err) - + // 测试正常情况 err = app.validateIngestTracesReq(context.Background(), &openapi.IngestTracesRequest{ Spans: []*span.InputSpan{ @@ -3491,17 +3491,17 @@ func TestOpenAPIApplication_validateIngestTracesReq(t *testing.T) { func TestOpenAPIApplication_validateIngestTracesReqByTenant(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() - + traceConfigMock := configmocks.NewMockITraceConfig(ctrl) app := &OpenAPIApplication{ traceConfig: traceConfigMock, } - + // 测试nil请求 traceConfigMock.EXPECT().GetTraceIngestTenantProducerCfg(gomock.Any()).Return(nil, nil) err := app.validateIngestTracesReqByTenant(context.Background(), "tenant", nil) assert.Error(t, err) - + // 测试超过最大span长度 traceConfigMock.EXPECT().GetTraceIngestTenantProducerCfg(gomock.Any()).Return(map[string]*config.IngestConfig{ "tenant": {MaxSpanLength: 1}, @@ -3510,7 +3510,7 @@ func TestOpenAPIApplication_validateIngestTracesReqByTenant(t *testing.T) { Spans: []*span.InputSpan{{}, {}}, }) assert.Error(t, err) - + // 测试正常情况 traceConfigMock.EXPECT().GetTraceIngestTenantProducerCfg(gomock.Any()).Return(nil, nil) err = app.validateIngestTracesReqByTenant(context.Background(), "tenant", &openapi.IngestTracesRequest{ @@ -3519,24 +3519,22 @@ func TestOpenAPIApplication_validateIngestTracesReqByTenant(t *testing.T) { assert.NoError(t, err) } - func TestOpenAPIApplication_unpackTenant(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() - + tenantMock := tenantmocks.NewMockITenantProvider(ctrl) app := &OpenAPIApplication{ tenant: tenantMock, } - + // 测试nil spans result := app.unpackTenant(context.Background(), nil) assert.Nil(t, result) - + // 测试正常情况 tenantMock.EXPECT().GetIngestTenant(gomock.Any(), gomock.Any()).Return("tenant1") result = app.unpackTenant(context.Background(), []*loop_span.Span{{SpanID: "test"}}) assert.Len(t, result, 1) assert.Len(t, result["tenant1"], 1) } - diff --git a/backend/modules/observability/infra/metrics/metrics_test.go b/backend/modules/observability/infra/metrics/metrics_test.go index 9ea40e666..0d275031d 100644 --- a/backend/modules/observability/infra/metrics/metrics_test.go +++ b/backend/modules/observability/infra/metrics/metrics_test.go @@ -194,7 +194,7 @@ func TestTraceMetricsImpl_EmitGetTrace(t *testing.T) { } } -func TestTraceMetricsImpl_EmitListSpansOapi(t *testing.T) { +func TestTraceMetricsImpl_EmitTraceOapi(t *testing.T) { type fields struct { spansMetrics infraMetrics.Metric } @@ -212,6 +212,7 @@ func TestTraceMetricsImpl_EmitListSpansOapi(t *testing.T) { name string fieldsGetter func(ctrl *gomock.Controller) fields args args + expectTags func(t *testing.T, tags []infraMetrics.T) }{ { name: "should not panic when spansMetrics is nil", @@ -220,29 +221,126 @@ func TestTraceMetricsImpl_EmitListSpansOapi(t *testing.T) { spansMetrics: nil, } }, - args: args{"1", 123, "coze", "llm", 1024, 0, time.Now(), false}, + args: args{"ListSpans", 123, "coze", "llm", 1024, 0, time.Now(), false}, }, { - name: "should emit metrics when spansMetrics is not nil", + name: "should emit metrics with correct tags for ListSpans", fieldsGetter: func(ctrl *gomock.Controller) fields { m := mocks.NewMockMetric(ctrl) - m.EXPECT().Emit(gomock.Any(), gomock.Any()).Times(1) + m.EXPECT().Emit(gomock.Any(), gomock.Any()).Do(func(tags []infraMetrics.T, values ...interface{}) { + // 验证标签 + expectedTags := map[string]string{ + tagMethod: "ListSpans", + tagSpaceID: "123", + tagIsErr: "false", + tagPlatformType: "coze", + tagSpanType: "llm", + tagErrCode: "0", + } + assert.Len(t, tags, 6) + for _, tag := range tags { + expectedValue, exists := expectedTags[tag.Name] + assert.True(t, exists, "Unexpected tag: %s", tag.Name) + assert.Equal(t, expectedValue, tag.Value, "Tag %s has wrong value", tag.Name) + } + // 验证指标值:3个指标(throughput counter, size counter, latency timer) + assert.Len(t, values, 3) + }).Times(1) return fields{ spansMetrics: m, } }, - args: args{"1", 123, "coze", "llm", 1024, 0, time.Now(), false}, + args: args{"ListSpans", 123, "coze", "llm", 1024, 0, time.Now(), false}, }, { - name: "should emit metrics with error", + name: "should emit metrics with correct tags for GetTrace", fieldsGetter: func(ctrl *gomock.Controller) fields { m := mocks.NewMockMetric(ctrl) - m.EXPECT().Emit(gomock.Any(), gomock.Any()).Times(1) + m.EXPECT().Emit(gomock.Any(), gomock.Any()).Do(func(tags []infraMetrics.T, values ...interface{}) { + expectedTags := map[string]string{ + tagMethod: "GetTrace", + tagSpaceID: "456", + tagIsErr: "false", + tagPlatformType: "dify", + tagSpanType: "workflow", + tagErrCode: "0", + } + assert.Len(t, tags, 6) + for _, tag := range tags { + expectedValue, exists := expectedTags[tag.Name] + assert.True(t, exists, "Unexpected tag: %s", tag.Name) + assert.Equal(t, expectedValue, tag.Value, "Tag %s has wrong value", tag.Name) + } + }).Times(1) + return fields{ + spansMetrics: m, + } + }, + args: args{"GetTrace", 456, "dify", "workflow", 2048, 0, time.Now(), false}, + }, + { + name: "should emit metrics with error tags", + fieldsGetter: func(ctrl *gomock.Controller) fields { + m := mocks.NewMockMetric(ctrl) + m.EXPECT().Emit(gomock.Any(), gomock.Any()).Do(func(tags []infraMetrics.T, values ...interface{}) { + expectedTags := map[string]string{ + tagMethod: "ListSpans", + tagSpaceID: "789", + tagIsErr: "true", + tagPlatformType: "openai", + tagSpanType: "chat", + tagErrCode: "500", + } + for _, tag := range tags { + expectedValue, exists := expectedTags[tag.Name] + assert.True(t, exists, "Unexpected tag: %s", tag.Name) + assert.Equal(t, expectedValue, tag.Value, "Tag %s has wrong value", tag.Name) + } + }).Times(1) + return fields{ + spansMetrics: m, + } + }, + args: args{"ListSpans", 789, "openai", "chat", 512, 500, time.Now(), true}, + }, + { + name: "should handle empty method and platform type", + fieldsGetter: func(ctrl *gomock.Controller) fields { + m := mocks.NewMockMetric(ctrl) + m.EXPECT().Emit(gomock.Any(), gomock.Any()).Do(func(tags []infraMetrics.T, values ...interface{}) { + expectedTags := map[string]string{ + tagMethod: "", + tagSpaceID: "0", + tagIsErr: "false", + tagPlatformType: "", + tagSpanType: "", + tagErrCode: "0", + } + for _, tag := range tags { + expectedValue, exists := expectedTags[tag.Name] + assert.True(t, exists, "Unexpected tag: %s", tag.Name) + assert.Equal(t, expectedValue, tag.Value, "Tag %s has wrong value", tag.Name) + } + }).Times(1) + return fields{ + spansMetrics: m, + } + }, + args: args{"", 0, "", "", 0, 0, time.Now(), false}, + }, + { + name: "should handle negative span size", + fieldsGetter: func(ctrl *gomock.Controller) fields { + m := mocks.NewMockMetric(ctrl) + m.EXPECT().Emit(gomock.Any(), gomock.Any()).Do(func(tags []infraMetrics.T, values ...interface{}) { + // 验证负数span size也能正确处理 + assert.Len(t, values, 3) + }).Times(1) return fields{ spansMetrics: m, } }, - args: args{"1", 456, "openai", "chat", 2048, 500, time.Now(), true}, + args: args{"GetTrace", 999, "coze", "agent", -100, 0, time.Now(), false}, }, } for _, tt := range tests { @@ -264,6 +362,97 @@ func TestTraceMetricsImpl_EmitListSpansOapi(t *testing.T) { } } +func TestTraceMetricsImpl_EmitTraceOapi_MetricValues(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockMetric := mocks.NewMockMetric(ctrl) + + // 测试指标值的正确性 + mockMetric.EXPECT().Emit(gomock.Any(), gomock.Any()).Do(func(tags []infraMetrics.T, values ...interface{}) { + // 验证有3个指标值:throughput counter, size counter, latency timer + assert.Len(t, values, 3) + + // 验证指标类型和后缀 + throughputCounter := values[0] + sizeCounter := values[1] + latencyTimer := values[2] + + assert.NotNil(t, throughputCounter) + assert.NotNil(t, sizeCounter) + assert.NotNil(t, latencyTimer) + }).Times(1) + + tr := &TraceMetricsImpl{ + spansMetrics: mockMetric, + } + + start := time.Now() + tr.EmitTraceOapi("TestMethod", 12345, "test_platform", "test_span", 1024, 200, start, true) +} + +func TestTraceMetricsImpl_EmitTraceOapi_Integration(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + // 测试与domain层接口的集成 + mockMetric := mocks.NewMockMetric(ctrl) + mockMetric.EXPECT().Emit(gomock.Any(), gomock.Any()).AnyTimes() + + tr := &TraceMetricsImpl{ + spansMetrics: mockMetric, + } + + // 验证实现了domain接口 + var domainMetrics metrics2.ITraceMetrics = tr + assert.NotNil(t, domainMetrics) + + // 测试所有接口方法 + start := time.Now() + domainMetrics.EmitListSpans(123, "llm", start, false) + domainMetrics.EmitGetTrace(456, start, true) + domainMetrics.EmitTraceOapi("TestMethod", 789, "coze", "workflow", 2048, 0, start, false) +} + +func TestTraceMetricsImpl_ConcurrentAccess(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockMetric := mocks.NewMockMetric(ctrl) + mockMetric.EXPECT().Emit(gomock.Any(), gomock.Any()).AnyTimes() + + tr := &TraceMetricsImpl{ + spansMetrics: mockMetric, + } + + // 并发安全性测试 + concurrency := 50 + done := make(chan bool, concurrency) + + for i := 0; i < concurrency; i++ { + go func(id int) { + defer func() { done <- true }() + + start := time.Now() + workspaceId := int64(id + 1000) + + // 并发调用EmitTraceOapi方法 + tr.EmitTraceOapi("ConcurrentTest", workspaceId, "test_platform", "test_span", int64(id*10), id%2, start, id%2 == 1) + }(i) + } + + // 等待所有goroutine完成 + timeout := time.After(5 * time.Second) + for i := 0; i < concurrency; i++ { + select { + case <-done: + // 成功完成 + case <-timeout: + t.Fatal("Concurrent test timed out") + } + } +} + func TestTraceQueryTagNames(t *testing.T) { expected := []string{ tagMethod, diff --git a/backend/modules/observability/infra/rpc/auth/mocks/auth_client_mock.go b/backend/modules/observability/infra/rpc/auth/mocks/auth_client_mock.go new file mode 100644 index 000000000..26aab398c --- /dev/null +++ b/backend/modules/observability/infra/rpc/auth/mocks/auth_client_mock.go @@ -0,0 +1,10 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: auth.go +// +// Generated by this command: +// +// mockgen -source=auth.go -destination=mocks/auth_client_mock.go -package=mocks +// + +// Package mocks is a generated GoMock package. +package mocks From ce83193ec9dc02636a45409dbda670eeab56f11c Mon Sep 17 00:00:00 2001 From: cuichen Date: Tue, 9 Sep 2025 17:48:48 +0800 Subject: [PATCH 23/29] trace openapi add UT --- .../observability/infra/config/trace_test.go | 3 +- .../observability/infra/rpc/auth/auth_test.go | 19 +++++------ .../infra/workspace/workspace_test.go | 33 ++++++++++--------- 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/backend/modules/observability/infra/config/trace_test.go b/backend/modules/observability/infra/config/trace_test.go index 2ad255c1b..999e53ba6 100755 --- a/backend/modules/observability/infra/config/trace_test.go +++ b/backend/modules/observability/infra/config/trace_test.go @@ -944,7 +944,6 @@ func TestNewTraceConfigCenter(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() f := tt.fieldsGetter(ctrl) - if tt.wantPanic { assert.Panics(t, func() { NewTraceConfigCenter(f.confP) @@ -961,4 +960,4 @@ func TestNewTraceConfigCenter(t *testing.T) { // Helper function to create string pointer func stringPtr(s string) *string { return &s -} \ No newline at end of file +} diff --git a/backend/modules/observability/infra/rpc/auth/auth_test.go b/backend/modules/observability/infra/rpc/auth/auth_test.go index edfb8ef64..6e549d085 100755 --- a/backend/modules/observability/infra/rpc/auth/auth_test.go +++ b/backend/modules/observability/infra/rpc/auth/auth_test.go @@ -541,12 +541,11 @@ func TestNewAuthProvider(t *testing.T) { func TestAuthProviderImpl_Interface(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() - mockClient := mocks.NewMockClient(ctrl) - + // Verify that AuthProviderImpl implements IAuthProvider interface var _ rpc.IAuthProvider = &AuthProviderImpl{} - + provider := NewAuthProvider(mockClient) assert.NotNil(t, provider) assert.IsType(t, &AuthProviderImpl{}, provider) @@ -555,24 +554,24 @@ func TestAuthProviderImpl_Interface(t *testing.T) { func TestAuthProviderImpl_ErrorCodes(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() - + mockClient := mocks.NewMockClient(ctrl) provider := &AuthProviderImpl{cli: mockClient} - + // Test invalid workspace ID error code err := provider.CheckWorkspacePermission(context.Background(), "read", "invalid") assert.NotNil(t, err) - + // Check if error is wrapped with correct error code assert.Contains(t, err.Error(), "internal error") assert.Contains(t, err.Error(), "internal error") // Test RPC error code mockClient.EXPECT().MCheckPermission(gomock.Any(), gomock.Any(), gomock.Any()). Return(nil, fmt.Errorf("rpc error")) - + err = provider.CheckWorkspacePermission(context.Background(), "read", "12345") assert.NotNil(t, err) - + // Test permission denied error code mockClient.EXPECT().MCheckPermission(gomock.Any(), gomock.Any(), gomock.Any()). Return(&auth.MCheckPermissionResponse{ @@ -581,7 +580,7 @@ func TestAuthProviderImpl_ErrorCodes(t *testing.T) { {IsAllowed: ptr.Of(false)}, }, }, nil) - + err = provider.CheckWorkspacePermission(context.Background(), "read", "12345") assert.NotNil(t, err) -} \ No newline at end of file +} diff --git a/backend/modules/observability/infra/workspace/workspace_test.go b/backend/modules/observability/infra/workspace/workspace_test.go index 1142431fd..50b60a376 100755 --- a/backend/modules/observability/infra/workspace/workspace_test.go +++ b/backend/modules/observability/infra/workspace/workspace_test.go @@ -83,7 +83,7 @@ func TestWorkspaceProviderImpl_GetIngestWorkSpaceID(t *testing.T) { func TestWorkspaceProviderImpl_GetQueryWorkSpaceID(t *testing.T) { type args struct { - ctx context.Context + ctx context.Context requestWorkspaceID int64 } tests := []struct { @@ -94,7 +94,7 @@ func TestWorkspaceProviderImpl_GetQueryWorkSpaceID(t *testing.T) { { name: "positive workspace id conversion", args: args{ - ctx: context.Background(), + ctx: context.Background(), requestWorkspaceID: 12345, }, want: "12345", @@ -102,7 +102,7 @@ func TestWorkspaceProviderImpl_GetQueryWorkSpaceID(t *testing.T) { { name: "negative workspace id conversion", args: args{ - ctx: context.Background(), + ctx: context.Background(), requestWorkspaceID: -1, }, want: "-1", @@ -110,7 +110,7 @@ func TestWorkspaceProviderImpl_GetQueryWorkSpaceID(t *testing.T) { { name: "zero workspace id conversion", args: args{ - ctx: context.Background(), + ctx: context.Background(), requestWorkspaceID: 0, }, want: "0", @@ -118,7 +118,7 @@ func TestWorkspaceProviderImpl_GetQueryWorkSpaceID(t *testing.T) { { name: "large positive workspace id conversion", args: args{ - ctx: context.Background(), + ctx: context.Background(), requestWorkspaceID: 9223372036854775807, // max int64 }, want: "9223372036854775807", @@ -126,7 +126,7 @@ func TestWorkspaceProviderImpl_GetQueryWorkSpaceID(t *testing.T) { { name: "large negative workspace id conversion", args: args{ - ctx: context.Background(), + ctx: context.Background(), requestWorkspaceID: -9223372036854775808, // min int64 }, want: "-9223372036854775808", @@ -164,14 +164,14 @@ func TestNewWorkspaceProvider(t *testing.T) { func TestWorkspaceProviderImpl_Interface(t *testing.T) { // Verify that WorkspaceProviderImpl implements IWorkSpaceProvider interface var _ workspace.IWorkSpaceProvider = &WorkspaceProviderImpl{} - + provider := NewWorkspaceProvider() assert.NotNil(t, provider) - + // Test interface methods exist and are callable workspaceID := provider.GetQueryWorkSpaceID(context.Background(), 123) assert.Equal(t, "123", workspaceID) - + spans := []*span.InputSpan{{WorkspaceID: "test"}} ingestID := provider.GetIngestWorkSpaceID(context.Background(), spans) assert.Equal(t, "test", ingestID) @@ -179,19 +179,20 @@ func TestWorkspaceProviderImpl_Interface(t *testing.T) { func TestWorkspaceProviderImpl_EdgeCases(t *testing.T) { provider := &WorkspaceProviderImpl{} - + ctx := context.Background() + // Test with nil context (should still work) - got := provider.GetQueryWorkSpaceID(nil, 456) + got := provider.GetQueryWorkSpaceID(ctx, 456) assert.Equal(t, "456", got) - + // Test with nil context for GetIngestWorkSpaceID spans := []*span.InputSpan{{WorkspaceID: "test_nil_ctx"}} - ingestID := provider.GetIngestWorkSpaceID(nil, spans) + ingestID := provider.GetIngestWorkSpaceID(ctx, spans) assert.Equal(t, "test_nil_ctx", ingestID) - + // Test with nil spans element - this would cause panic in the actual code // So we test the actual behavior which is to return empty string for empty array emptySpans := []*span.InputSpan{} - emptyID := provider.GetIngestWorkSpaceID(context.Background(), emptySpans) + emptyID := provider.GetIngestWorkSpaceID(ctx, emptySpans) assert.Equal(t, "", emptyID) -} \ No newline at end of file +} From 3e5ea15671c8de136a6a79455d19aa890adb9aae Mon Sep 17 00:00:00 2001 From: cuichen Date: Tue, 9 Sep 2025 19:12:32 +0800 Subject: [PATCH 24/29] =?UTF-8?q?test:=20[Coda]=20=E8=A1=A5=E5=85=85trace?= =?UTF-8?q?=20service=20UT=E6=8F=90=E5=8D=87=E8=A6=86=E7=9B=96=E7=8E=87?= =?UTF-8?q?=E5=88=B082.7%?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Coda --- .../trace/service/trace_service_test.go | 457 +++++++++++++++++- 1 file changed, 455 insertions(+), 2 deletions(-) diff --git a/backend/modules/observability/domain/trace/service/trace_service_test.go b/backend/modules/observability/domain/trace/service/trace_service_test.go index 23f30a0d9..b00c10bf9 100644 --- a/backend/modules/observability/domain/trace/service/trace_service_test.go +++ b/backend/modules/observability/domain/trace/service/trace_service_test.go @@ -2532,6 +2532,304 @@ func TestTraceServiceImpl_ListSpansOApi(t *testing.T) { want *ListSpansOApiResp wantErr bool }{ + { + name: "list spans oapi successfully", + fieldsGetter: func(ctrl *gomock.Controller) fields { + repoMock := repomocks.NewMockITraceRepo(ctrl) + repoMock.EXPECT().ListSpans(gomock.Any(), gomock.Any()).Return(&repo.ListSpansResult{ + Spans: loop_span.SpanList{ + { + TraceID: "trace-123", + SpanID: "span-456", + }, + }, + PageToken: "next-token", + HasMore: true, + }, nil) + + filterFactoryMock := filtermocks.NewMockPlatformFilterFactory(ctrl) + filterMock := filtermocks.NewMockFilter(ctrl) + filterMock.EXPECT().BuildBasicSpanFilter(gomock.Any(), gomock.Any()).Return([]*loop_span.FilterField{ + { + FieldName: loop_span.SpanFieldSpaceId, + FieldType: loop_span.FieldTypeString, + Values: []string{"123"}, + QueryType: ptr.Of(loop_span.QueryTypeEnumIn), + }, + }, false, nil) + filterMock.EXPECT().BuildALLSpanFilter(gomock.Any(), gomock.Any()).Return(nil, nil) + filterFactoryMock.EXPECT().GetFilter(gomock.Any(), gomock.Any()).Return(filterMock, nil) + + buildHelper := NewTraceFilterProcessorBuilder(filterFactoryMock, nil, nil, nil, nil, nil, nil) + + return fields{ + traceRepo: repoMock, + buildHelper: buildHelper, + } + }, + args: args{ + ctx: context.Background(), + req: &ListSpansOApiReq{ + WorkspaceID: 123, + Tenants: []string{"tenant1"}, + StartTime: 1640995200000, + EndTime: 1640995800000, + Limit: 100, + PlatformType: loop_span.PlatformCozeLoop, + SpanListType: loop_span.SpanListTypeAllSpan, + }, + }, + want: &ListSpansOApiResp{ + Spans: loop_span.SpanList{ + { + TraceID: "trace-123", + SpanID: "span-456", + }, + }, + NextPageToken: "next-token", + HasMore: true, + }, + wantErr: false, + }, + { + name: "list spans oapi with empty builtin filter", + fieldsGetter: func(ctrl *gomock.Controller) fields { + filterFactoryMock := filtermocks.NewMockPlatformFilterFactory(ctrl) + filterMock := filtermocks.NewMockFilter(ctrl) + filterMock.EXPECT().BuildBasicSpanFilter(gomock.Any(), gomock.Any()).Return([]*loop_span.FilterField{}, false, nil) + filterFactoryMock.EXPECT().GetFilter(gomock.Any(), gomock.Any()).Return(filterMock, nil) + + buildHelper := NewTraceFilterProcessorBuilder(filterFactoryMock, nil, nil, nil, nil, nil, nil) + + return fields{ + + buildHelper: buildHelper, + } + }, + args: args{ + ctx: context.Background(), + req: &ListSpansOApiReq{ + WorkspaceID: 123, + Tenants: []string{"tenant1"}, + StartTime: 1640995200000, + EndTime: 1640995800000, + Limit: 100, + PlatformType: loop_span.PlatformCozeLoop, + SpanListType: loop_span.SpanListTypeAllSpan, + }, + }, + want: &ListSpansOApiResp{ + Spans: loop_span.SpanList{}, + }, + wantErr: false, + }, + { + name: "list spans oapi with multiple processors", + fieldsGetter: func(ctrl *gomock.Controller) fields { + repoMock := repomocks.NewMockITraceRepo(ctrl) + repoMock.EXPECT().ListSpans(gomock.Any(), gomock.Any()).Return(&repo.ListSpansResult{ + Spans: loop_span.SpanList{ + { + TraceID: "trace-123", + SpanID: "span-456", + WorkspaceID: "123", + }, + }, + PageToken: "", + HasMore: false, + }, nil) + + filterFactoryMock := filtermocks.NewMockPlatformFilterFactory(ctrl) + filterMock := filtermocks.NewMockFilter(ctrl) + filterMock.EXPECT().BuildBasicSpanFilter(gomock.Any(), gomock.Any()).Return([]*loop_span.FilterField{ + { + FieldName: loop_span.SpanFieldSpaceId, + FieldType: loop_span.FieldTypeString, + Values: []string{"123"}, + QueryType: ptr.Of(loop_span.QueryTypeEnumIn), + }, + }, false, nil) + filterMock.EXPECT().BuildALLSpanFilter(gomock.Any(), gomock.Any()).Return(nil, nil) + filterFactoryMock.EXPECT().GetFilter(gomock.Any(), gomock.Any()).Return(filterMock, nil) + + buildHelper := NewTraceFilterProcessorBuilder(filterFactoryMock, nil, nil, nil, nil, nil, + []span_processor.Factory{span_processor.NewCheckProcessorFactory()}) + + return fields{ + traceRepo: repoMock, + buildHelper: buildHelper, + } + }, + args: args{ + ctx: context.Background(), + req: &ListSpansOApiReq{ + WorkspaceID: 123, + Tenants: []string{"tenant1"}, + StartTime: 1640995200000, + EndTime: 1640995800000, + Limit: 100, + PlatformType: loop_span.PlatformCozeLoop, + SpanListType: loop_span.SpanListTypeAllSpan, + }, + }, + want: &ListSpansOApiResp{ + Spans: loop_span.SpanList{ + { + TraceID: "trace-123", + SpanID: "span-456", + WorkspaceID: "123", + }, + }, + NextPageToken: "", + HasMore: false, + }, + wantErr: false, + }, + { + name: "list spans oapi failed due to platform filter error", + fieldsGetter: func(ctrl *gomock.Controller) fields { + filterFactoryMock := filtermocks.NewMockPlatformFilterFactory(ctrl) + filterFactoryMock.EXPECT().GetFilter(gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("platform filter error")) + + buildHelper := NewTraceFilterProcessorBuilder(filterFactoryMock, nil, nil, nil, nil, nil, nil) + + return fields{ + buildHelper: buildHelper, + } + }, + args: args{ + ctx: context.Background(), + req: &ListSpansOApiReq{ + WorkspaceID: 123, + Tenants: []string{"tenant1"}, + StartTime: 1640995200000, + EndTime: 1640995800000, + Limit: 100, + PlatformType: loop_span.PlatformCozeLoop, + SpanListType: loop_span.SpanListTypeAllSpan, + }, + }, + wantErr: true, + }, + { + name: "list spans oapi failed due to builtin filter error", + fieldsGetter: func(ctrl *gomock.Controller) fields { + filterFactoryMock := filtermocks.NewMockPlatformFilterFactory(ctrl) + filterMock := filtermocks.NewMockFilter(ctrl) + filterMock.EXPECT().BuildBasicSpanFilter(gomock.Any(), gomock.Any()).Return(nil, false, fmt.Errorf("builtin filter error")) + filterFactoryMock.EXPECT().GetFilter(gomock.Any(), gomock.Any()).Return(filterMock, nil) + + buildHelper := NewTraceFilterProcessorBuilder(filterFactoryMock, nil, nil, nil, nil, nil, nil) + + return fields{ + buildHelper: buildHelper, + } + }, + args: args{ + ctx: context.Background(), + req: &ListSpansOApiReq{ + WorkspaceID: 123, + Tenants: []string{"tenant1"}, + StartTime: 1640995200000, + EndTime: 1640995800000, + Limit: 100, + PlatformType: loop_span.PlatformCozeLoop, + SpanListType: loop_span.SpanListTypeAllSpan, + }, + }, + wantErr: true, + }, + { + name: "list spans oapi failed due to repo error", + fieldsGetter: func(ctrl *gomock.Controller) fields { + repoMock := repomocks.NewMockITraceRepo(ctrl) + repoMock.EXPECT().ListSpans(gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("repo error")) + + filterFactoryMock := filtermocks.NewMockPlatformFilterFactory(ctrl) + filterMock := filtermocks.NewMockFilter(ctrl) + filterMock.EXPECT().BuildBasicSpanFilter(gomock.Any(), gomock.Any()).Return([]*loop_span.FilterField{ + { + FieldName: loop_span.SpanFieldSpaceId, + FieldType: loop_span.FieldTypeString, + Values: []string{"123"}, + QueryType: ptr.Of(loop_span.QueryTypeEnumIn), + }, + }, false, nil) + filterMock.EXPECT().BuildALLSpanFilter(gomock.Any(), gomock.Any()).Return(nil, nil) + filterFactoryMock.EXPECT().GetFilter(gomock.Any(), gomock.Any()).Return(filterMock, nil) + + buildHelper := NewTraceFilterProcessorBuilder(filterFactoryMock, nil, nil, nil, nil, nil, nil) + + return fields{ + traceRepo: repoMock, + buildHelper: buildHelper, + } + }, + args: args{ + ctx: context.Background(), + req: &ListSpansOApiReq{ + WorkspaceID: 123, + Tenants: []string{"tenant1"}, + StartTime: 1640995200000, + EndTime: 1640995800000, + Limit: 100, + PlatformType: loop_span.PlatformCozeLoop, + SpanListType: loop_span.SpanListTypeAllSpan, + }, + }, + wantErr: true, + }, + { + name: "list spans oapi failed due to processor transform error", + fieldsGetter: func(ctrl *gomock.Controller) fields { + repoMock := repomocks.NewMockITraceRepo(ctrl) + repoMock.EXPECT().ListSpans(gomock.Any(), gomock.Any()).Return(&repo.ListSpansResult{ + Spans: loop_span.SpanList{ + { + TraceID: "trace-123", + SpanID: "span-456", + WorkspaceID: "1234", + }, + }, + PageToken: "", + HasMore: false, + }, nil) + + filterFactoryMock := filtermocks.NewMockPlatformFilterFactory(ctrl) + filterMock := filtermocks.NewMockFilter(ctrl) + filterMock.EXPECT().BuildBasicSpanFilter(gomock.Any(), gomock.Any()).Return([]*loop_span.FilterField{ + { + FieldName: loop_span.SpanFieldSpaceId, + FieldType: loop_span.FieldTypeString, + Values: []string{"123"}, + QueryType: ptr.Of(loop_span.QueryTypeEnumIn), + }, + }, false, nil) + filterMock.EXPECT().BuildALLSpanFilter(gomock.Any(), gomock.Any()).Return(nil, nil) + filterFactoryMock.EXPECT().GetFilter(gomock.Any(), gomock.Any()).Return(filterMock, nil) + + buildHelper := NewTraceFilterProcessorBuilder(filterFactoryMock, nil, nil, nil, nil, nil, + []span_processor.Factory{span_processor.NewCheckProcessorFactory()}) + + return fields{ + traceRepo: repoMock, + buildHelper: buildHelper, + } + }, + args: args{ + ctx: context.Background(), + req: &ListSpansOApiReq{ + WorkspaceID: 123, + Tenants: []string{"tenant1"}, + StartTime: 1640995200000, + EndTime: 1640995800000, + Limit: 100, + PlatformType: loop_span.PlatformCozeLoop, + SpanListType: loop_span.SpanListTypeAllSpan, + }, + }, + wantErr: true, + }, { name: "list spans failed due to invalid filter", fieldsGetter: func(ctrl *gomock.Controller) fields { @@ -2565,8 +2863,7 @@ func TestTraceServiceImpl_ListSpansOApi(t *testing.T) { }, }, wantErr: true, - }, - } + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctrl := gomock.NewController(t) @@ -2584,3 +2881,159 @@ func TestTraceServiceImpl_ListSpansOApi(t *testing.T) { }) } } + +func TestTraceFilterProcessorBuilderImpl_BuildListSpansOApiProcessors(t *testing.T) { + tests := []struct { + name string + listSpansOApiProcessorFactories []span_processor.Factory + want int + wantErr bool + }{ + { + name: "build processors successfully with empty factories", + listSpansOApiProcessorFactories: []span_processor.Factory{}, + want: 0, + wantErr: false, + }, + { + name: "build processors successfully with multiple factories", + listSpansOApiProcessorFactories: []span_processor.Factory{ + span_processor.NewCheckProcessorFactory(), + span_processor.NewCheckProcessorFactory(), + }, + want: 2, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + filterFactoryMock := filtermocks.NewMockPlatformFilterFactory(ctrl) + builder := NewTraceFilterProcessorBuilder( + filterFactoryMock, + nil, + nil, + nil, + nil, + nil, + tt.listSpansOApiProcessorFactories, + ) + + got, err := builder.BuildListSpansOApiProcessors(context.Background(), span_processor.Settings{ + WorkspaceId: 123, + QueryStartTime: 1640995200000, + QueryEndTime: 1640995800000, + }) + + assert.Equal(t, tt.wantErr, err != nil) + if !tt.wantErr { + assert.Equal(t, tt.want, len(got)) + } + }) + } +} + +func TestTraceFilterProcessorBuilderImpl_BuildIngestTraceProcessors_ErrorHandling(t *testing.T) { + tests := []struct { + name string + ingestTraceProcessorFactories []span_processor.Factory + want int + wantErr bool + }{ + { + name: "build ingest processors successfully with empty factories", + ingestTraceProcessorFactories: []span_processor.Factory{}, + want: 0, + wantErr: false, + }, + { + name: "build ingest processors successfully with multiple factories", + ingestTraceProcessorFactories: []span_processor.Factory{ + span_processor.NewCheckProcessorFactory(), + }, + want: 1, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + filterFactoryMock := filtermocks.NewMockPlatformFilterFactory(ctrl) + + builder := NewTraceFilterProcessorBuilder( + filterFactoryMock, + nil, + nil, + nil, + tt.ingestTraceProcessorFactories, + nil, + nil, + ) + + got, err := builder.BuildIngestTraceProcessors(context.Background(), span_processor.Settings{ + Tenant: "test-tenant", + }) + + assert.Equal(t, tt.wantErr, err != nil) + if !tt.wantErr { + assert.Equal(t, tt.want, len(got)) + } + }) + } +} + +func TestTraceFilterProcessorBuilderImpl_BuildSearchTraceOApiProcessors_ErrorHandling(t *testing.T) { + tests := []struct { + name string + searchTraceOApiProcessorFactories []span_processor.Factory + want int + wantErr bool + }{ + { + name: "build search trace oapi processors successfully with empty factories", + searchTraceOApiProcessorFactories: []span_processor.Factory{}, + want: 0, + wantErr: false, + }, + { + name: "build search trace oapi processors successfully with multiple factories", + searchTraceOApiProcessorFactories: []span_processor.Factory{ + span_processor.NewCheckProcessorFactory(), + }, + want: 1, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + filterFactoryMock := filtermocks.NewMockPlatformFilterFactory(ctrl) + builder := NewTraceFilterProcessorBuilder( + filterFactoryMock, + nil, + nil, + nil, + nil, + tt.searchTraceOApiProcessorFactories, + nil, + ) + + got, err := builder.BuildSearchTraceOApiProcessors(context.Background(), span_processor.Settings{ + WorkspaceId: 123, + QueryStartTime: 1640995200000, + QueryEndTime: 1640995800000, + }) + + assert.Equal(t, tt.wantErr, err != nil) + if !tt.wantErr { + assert.Equal(t, tt.want, len(got)) + } + }) + } +} From 3103c2d62f0708893262af4a74494a1594b16592 Mon Sep 17 00:00:00 2001 From: cuichen Date: Tue, 9 Sep 2025 19:30:15 +0800 Subject: [PATCH 25/29] trace openapi fail fast --- .../observability/application/openapi.go | 16 +++--- .../trace/service/trace_service_test.go | 57 +++++++++---------- 2 files changed, 36 insertions(+), 37 deletions(-) diff --git a/backend/modules/observability/application/openapi.go b/backend/modules/observability/application/openapi.go index 1a9cee02f..050a88664 100644 --- a/backend/modules/observability/application/openapi.go +++ b/backend/modules/observability/application/openapi.go @@ -96,15 +96,15 @@ func (o *OpenAPIApplication) IngestTraces(ctx context.Context, req *openapi.Inge spanMap := o.unpackSpace(ctx, req.Spans) connectorUid := session.UserIDInCtxOrEmpty(ctx) for workspaceId := range spanMap { - // check permission - if err := o.auth.CheckIngestPermission(ctx, workspaceId); err != nil { - return nil, err - } - // check benefit workSpaceIdNum, err := strconv.ParseInt(workspaceId, 10, 64) if err != nil { return nil, errorx.NewByCode(obErrorx.CommercialCommonInvalidParamCodeCode, errorx.WithExtraMsg("invalid workspace_id")) } + // check permission + if err = o.auth.CheckIngestPermission(ctx, workspaceId); err != nil { + return nil, err + } + // check benefit benefitRes, err := o.benefit.CheckTraceBenefit(ctx, &benefit.CheckTraceBenefitParams{ ConnectorUID: connectorUid, SpaceID: workSpaceIdNum, @@ -234,13 +234,13 @@ func (o *OpenAPIApplication) OtelIngestTraces(ctx context.Context, req *openapi. partialFailSpanNumber := 0 partialErrMessage := "" for workspaceId, otelSpans := range spansMap { - if e := o.auth.CheckIngestPermission(ctx, workspaceId); e != nil { - return nil, e - } workSpaceIdNum, e := strconv.ParseInt(workspaceId, 10, 64) if e != nil { return nil, errorx.NewByCode(obErrorx.CommercialCommonInvalidParamCodeCode, errorx.WithExtraMsg("invalid workspace_id")) } + if e = o.auth.CheckIngestPermission(ctx, workspaceId); e != nil { + return nil, e + } connectorUid := session.UserIDInCtxOrEmpty(ctx) benefitRes, e := o.benefit.CheckTraceBenefit(ctx, &benefit.CheckTraceBenefitParams{ ConnectorUID: connectorUid, diff --git a/backend/modules/observability/domain/trace/service/trace_service_test.go b/backend/modules/observability/domain/trace/service/trace_service_test.go index b00c10bf9..80ca229b2 100644 --- a/backend/modules/observability/domain/trace/service/trace_service_test.go +++ b/backend/modules/observability/domain/trace/service/trace_service_test.go @@ -2602,7 +2602,6 @@ func TestTraceServiceImpl_ListSpansOApi(t *testing.T) { buildHelper := NewTraceFilterProcessorBuilder(filterFactoryMock, nil, nil, nil, nil, nil, nil) return fields{ - buildHelper: buildHelper, } }, @@ -2863,7 +2862,7 @@ func TestTraceServiceImpl_ListSpansOApi(t *testing.T) { }, }, wantErr: true, - }, } + }} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctrl := gomock.NewController(t) @@ -2884,25 +2883,25 @@ func TestTraceServiceImpl_ListSpansOApi(t *testing.T) { func TestTraceFilterProcessorBuilderImpl_BuildListSpansOApiProcessors(t *testing.T) { tests := []struct { - name string + name string listSpansOApiProcessorFactories []span_processor.Factory - want int - wantErr bool + want int + wantErr bool }{ { - name: "build processors successfully with empty factories", + name: "build processors successfully with empty factories", listSpansOApiProcessorFactories: []span_processor.Factory{}, - want: 0, - wantErr: false, + want: 0, + wantErr: false, }, { - name: "build processors successfully with multiple factories", + name: "build processors successfully with multiple factories", listSpansOApiProcessorFactories: []span_processor.Factory{ span_processor.NewCheckProcessorFactory(), span_processor.NewCheckProcessorFactory(), }, - want: 2, - wantErr: false, + want: 2, + wantErr: false, }, } for _, tt := range tests { @@ -2937,24 +2936,24 @@ func TestTraceFilterProcessorBuilderImpl_BuildListSpansOApiProcessors(t *testing func TestTraceFilterProcessorBuilderImpl_BuildIngestTraceProcessors_ErrorHandling(t *testing.T) { tests := []struct { - name string + name string ingestTraceProcessorFactories []span_processor.Factory - want int - wantErr bool + want int + wantErr bool }{ { - name: "build ingest processors successfully with empty factories", + name: "build ingest processors successfully with empty factories", ingestTraceProcessorFactories: []span_processor.Factory{}, - want: 0, - wantErr: false, + want: 0, + wantErr: false, }, { - name: "build ingest processors successfully with multiple factories", + name: "build ingest processors successfully with multiple factories", ingestTraceProcessorFactories: []span_processor.Factory{ span_processor.NewCheckProcessorFactory(), }, - want: 1, - wantErr: false, + want: 1, + wantErr: false, }, } for _, tt := range tests { @@ -2988,24 +2987,24 @@ func TestTraceFilterProcessorBuilderImpl_BuildIngestTraceProcessors_ErrorHandlin func TestTraceFilterProcessorBuilderImpl_BuildSearchTraceOApiProcessors_ErrorHandling(t *testing.T) { tests := []struct { - name string + name string searchTraceOApiProcessorFactories []span_processor.Factory - want int - wantErr bool + want int + wantErr bool }{ { - name: "build search trace oapi processors successfully with empty factories", + name: "build search trace oapi processors successfully with empty factories", searchTraceOApiProcessorFactories: []span_processor.Factory{}, - want: 0, - wantErr: false, + want: 0, + wantErr: false, }, { - name: "build search trace oapi processors successfully with multiple factories", + name: "build search trace oapi processors successfully with multiple factories", searchTraceOApiProcessorFactories: []span_processor.Factory{ span_processor.NewCheckProcessorFactory(), }, - want: 1, - wantErr: false, + want: 1, + wantErr: false, }, } for _, tt := range tests { From 855674f6010f9510d569b561773ab2a57f1ff99a Mon Sep 17 00:00:00 2001 From: cuichen Date: Tue, 9 Sep 2025 19:42:12 +0800 Subject: [PATCH 26/29] trace openapi fail fast --- .../observability/domain/trace/service/trace_service_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/modules/observability/domain/trace/service/trace_service_test.go b/backend/modules/observability/domain/trace/service/trace_service_test.go index 80ca229b2..c38827f30 100644 --- a/backend/modules/observability/domain/trace/service/trace_service_test.go +++ b/backend/modules/observability/domain/trace/service/trace_service_test.go @@ -2862,7 +2862,8 @@ func TestTraceServiceImpl_ListSpansOApi(t *testing.T) { }, }, wantErr: true, - }} + }, + } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctrl := gomock.NewController(t) From f9cad145d2b6ba77e82c1cd3aee28d1f34207ba8 Mon Sep 17 00:00:00 2001 From: cuichen Date: Tue, 9 Sep 2025 19:58:31 +0800 Subject: [PATCH 27/29] trace openapi fail fast --- backend/modules/observability/application/openapi_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/modules/observability/application/openapi_test.go b/backend/modules/observability/application/openapi_test.go index bd747a7b7..5436b8b6c 100644 --- a/backend/modules/observability/application/openapi_test.go +++ b/backend/modules/observability/application/openapi_test.go @@ -1036,7 +1036,7 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { fieldsGetter: func(ctrl *gomock.Controller) fields { traceServiceMock := servicemocks.NewMockITraceService(ctrl) authMock := rpcmocks.NewMockIAuthProvider(ctrl) - authMock.EXPECT().CheckIngestPermission(gomock.Any(), "invalid").Return(nil) + authMock.EXPECT().CheckIngestPermission(gomock.Any(), "invalid").Return(nil).AnyTimes() benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) @@ -2967,7 +2967,7 @@ func TestOpenAPIApplication_IngestTraces_AdditionalScenarios(t *testing.T) { fieldsGetter: func(ctrl *gomock.Controller) fields { traceServiceMock := servicemocks.NewMockITraceService(ctrl) authMock := rpcmocks.NewMockIAuthProvider(ctrl) - authMock.EXPECT().CheckIngestPermission(gomock.Any(), gomock.Any()).Return(nil) + authMock.EXPECT().CheckIngestPermission(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) From 3c4127caf1055e3d55a3fa805fbca4b2cf2ba79d Mon Sep 17 00:00:00 2001 From: cuichen Date: Wed, 10 Sep 2025 11:47:51 +0800 Subject: [PATCH 28/29] trace openapi update --- .../openapi/coze.loop.prompt.openapi.go | 77 ++++++++++++------- .../domain/component/metrics/metrics.go | 2 +- .../domain/component/metrics/mocks/metrics.go | 4 +- .../trace/span_filter/cozeloop_filter.go | 2 +- .../trace/span_filter/cozeloop_filter_test.go | 8 +- .../trace/span_filter/eval_target_filter.go | 2 +- .../span_filter/eval_target_filter_test.go | 8 +- .../trace/span_filter/evaluator_filter.go | 2 +- .../span_filter/evaluator_filter_test.go | 2 +- .../trace/service/trace/span_filter/filter.go | 2 +- .../trace/span_filter/prompt_filter.go | 2 +- .../trace/span_filter/prompt_filter_test.go | 2 +- .../domain/trace/service/trace_service.go | 2 +- .../observability/infra/metrics/metrics.go | 6 +- .../coze.loop.observability.openapi.thrift | 2 +- 15 files changed, 74 insertions(+), 49 deletions(-) diff --git a/backend/kitex_gen/coze/loop/prompt/openapi/coze.loop.prompt.openapi.go b/backend/kitex_gen/coze/loop/prompt/openapi/coze.loop.prompt.openapi.go index f0ff648fe..3abac5b11 100644 --- a/backend/kitex_gen/coze/loop/prompt/openapi/coze.loop.prompt.openapi.go +++ b/backend/kitex_gen/coze/loop/prompt/openapi/coze.loop.prompt.openapi.go @@ -1024,11 +1024,15 @@ func (p *PromptResultData) Field1DeepEqual(src []*PromptResult_) bool { } type ExecuteRequest struct { - WorkspaceID *int64 `thrift:"workspace_id,1,optional" frugal:"1,optional,i64" json:"workspace_id" form:"workspace_id" ` - PromptIdentifier *PromptQuery `thrift:"prompt_identifier,2,optional" frugal:"2,optional,PromptQuery" form:"prompt_identifier" json:"prompt_identifier,omitempty"` - VariableVals []*VariableVal `thrift:"variable_vals,10,optional" frugal:"10,optional,list" form:"variable_vals" json:"variable_vals,omitempty"` - Messages []*Message `thrift:"messages,11,optional" frugal:"11,optional,list" form:"messages" json:"messages,omitempty"` - Base *base.Base `thrift:"Base,255,optional" frugal:"255,optional,base.Base" form:"Base" json:"Base,omitempty" query:"Base"` + // 工作空间ID + WorkspaceID *int64 `thrift:"workspace_id,1,optional" frugal:"1,optional,i64" json:"workspace_id" form:"workspace_id" ` + // Prompt 标识 + PromptIdentifier *PromptQuery `thrift:"prompt_identifier,2,optional" frugal:"2,optional,PromptQuery" form:"prompt_identifier" json:"prompt_identifier,omitempty"` + // 变量值 + VariableVals []*VariableVal `thrift:"variable_vals,10,optional" frugal:"10,optional,list" form:"variable_vals" json:"variable_vals,omitempty"` + // 消息 + Messages []*Message `thrift:"messages,11,optional" frugal:"11,optional,list" form:"messages" json:"messages,omitempty"` + Base *base.Base `thrift:"Base,255,optional" frugal:"255,optional,base.Base" form:"Base" json:"Base,omitempty" query:"Base"` } func NewExecuteRequest() *ExecuteRequest { @@ -1935,9 +1939,12 @@ func (p *ExecuteResponse) Field255DeepEqual(src *base.BaseResp) bool { } type ExecuteData struct { - Message *Message `thrift:"message,1,optional" frugal:"1,optional,Message" form:"message" json:"message,omitempty" query:"message"` - FinishReason *string `thrift:"finish_reason,2,optional" frugal:"2,optional,string" form:"finish_reason" json:"finish_reason,omitempty" query:"finish_reason"` - Usage *TokenUsage `thrift:"usage,3,optional" frugal:"3,optional,TokenUsage" form:"usage" json:"usage,omitempty" query:"usage"` + // 消息 + Message *Message `thrift:"message,1,optional" frugal:"1,optional,Message" form:"message" json:"message,omitempty" query:"message"` + // 结束原因 + FinishReason *string `thrift:"finish_reason,2,optional" frugal:"2,optional,string" form:"finish_reason" json:"finish_reason,omitempty" query:"finish_reason"` + // token消耗 + Usage *TokenUsage `thrift:"usage,3,optional" frugal:"3,optional,TokenUsage" form:"usage" json:"usage,omitempty" query:"usage"` } func NewExecuteData() *ExecuteData { @@ -2727,11 +2734,14 @@ func (p *ExecuteStreamingResponse) Field255DeepEqual(src *base.BaseResp) bool { } type ExecuteStreamingData struct { - Code *int32 `thrift:"code,1,optional" frugal:"1,optional,i32" form:"code" json:"code,omitempty" query:"code"` - Msg *string `thrift:"msg,2,optional" frugal:"2,optional,string" form:"msg" json:"msg,omitempty" query:"msg"` - Message *Message `thrift:"message,3,optional" frugal:"3,optional,Message" form:"message" json:"message,omitempty" query:"message"` - FinishReason *string `thrift:"finish_reason,4,optional" frugal:"4,optional,string" form:"finish_reason" json:"finish_reason,omitempty" query:"finish_reason"` - Usage *TokenUsage `thrift:"usage,5,optional" frugal:"5,optional,TokenUsage" form:"usage" json:"usage,omitempty" query:"usage"` + Code *int32 `thrift:"code,1,optional" frugal:"1,optional,i32" form:"code" json:"code,omitempty" query:"code"` + Msg *string `thrift:"msg,2,optional" frugal:"2,optional,string" form:"msg" json:"msg,omitempty" query:"msg"` + // 消息 + Message *Message `thrift:"message,3,optional" frugal:"3,optional,Message" form:"message" json:"message,omitempty" query:"message"` + // 结束原因 + FinishReason *string `thrift:"finish_reason,4,optional" frugal:"4,optional,string" form:"finish_reason" json:"finish_reason,omitempty" query:"finish_reason"` + // token消耗 + Usage *TokenUsage `thrift:"usage,5,optional" frugal:"5,optional,TokenUsage" form:"usage" json:"usage,omitempty" query:"usage"` } func NewExecuteStreamingData() *ExecuteStreamingData { @@ -3200,9 +3210,12 @@ func (p *ExecuteStreamingData) Field5DeepEqual(src *TokenUsage) bool { } type PromptQuery struct { + // prompt_key PromptKey *string `thrift:"prompt_key,1,optional" frugal:"1,optional,string" form:"prompt_key" json:"prompt_key,omitempty" query:"prompt_key"` - Version *string `thrift:"version,2,optional" frugal:"2,optional,string" form:"version" json:"version,omitempty" query:"version"` - Label *string `thrift:"label,3,optional" frugal:"3,optional,string" form:"label" json:"label,omitempty" query:"label"` + // prompt版本 + Version *string `thrift:"version,2,optional" frugal:"2,optional,string" form:"version" json:"version,omitempty" query:"version"` + // prompt版本标识(如果version不为空,该字段会被忽略) + Label *string `thrift:"label,3,optional" frugal:"3,optional,string" form:"label" json:"label,omitempty" query:"label"` } func NewPromptQuery() *PromptQuery { @@ -4985,12 +4998,18 @@ func (p *ToolCallConfig) Field1DeepEqual(src *ToolChoiceType) bool { } type Message struct { - Role *Role `thrift:"role,1,optional" frugal:"1,optional,string" form:"role" json:"role,omitempty" query:"role"` - Content *string `thrift:"content,2,optional" frugal:"2,optional,string" form:"content" json:"content,omitempty" query:"content"` - Parts []*ContentPart `thrift:"parts,3,optional" frugal:"3,optional,list" form:"parts" json:"parts,omitempty" query:"parts"` - ReasoningContent *string `thrift:"reasoning_content,4,optional" frugal:"4,optional,string" form:"reasoning_content" json:"reasoning_content,omitempty" query:"reasoning_content"` - ToolCallID *string `thrift:"tool_call_id,5,optional" frugal:"5,optional,string" form:"tool_call_id" json:"tool_call_id,omitempty" query:"tool_call_id"` - ToolCalls []*ToolCall `thrift:"tool_calls,6,optional" frugal:"6,optional,list" form:"tool_calls" json:"tool_calls,omitempty" query:"tool_calls"` + // 角色 + Role *Role `thrift:"role,1,optional" frugal:"1,optional,string" form:"role" json:"role,omitempty" query:"role"` + // 消息内容 + Content *string `thrift:"content,2,optional" frugal:"2,optional,string" form:"content" json:"content,omitempty" query:"content"` + // 多模态内容 + Parts []*ContentPart `thrift:"parts,3,optional" frugal:"3,optional,list" form:"parts" json:"parts,omitempty" query:"parts"` + // 推理思考内容 + ReasoningContent *string `thrift:"reasoning_content,4,optional" frugal:"4,optional,string" form:"reasoning_content" json:"reasoning_content,omitempty" query:"reasoning_content"` + // tool调用ID(role为tool时有效) + ToolCallID *string `thrift:"tool_call_id,5,optional" frugal:"5,optional,string" form:"tool_call_id" json:"tool_call_id,omitempty" query:"tool_call_id"` + // tool调用(role为assistant时有效) + ToolCalls []*ToolCall `thrift:"tool_calls,6,optional" frugal:"6,optional,list" form:"tool_calls" json:"tool_calls,omitempty" query:"tool_calls"` } func NewMessage() *Message { @@ -8233,10 +8252,14 @@ func (p *LLMConfig) Field7DeepEqual(src *bool) bool { } type VariableVal struct { - Key *string `thrift:"key,1,optional" frugal:"1,optional,string" form:"key" json:"key,omitempty" query:"key"` - Value *string `thrift:"value,2,optional" frugal:"2,optional,string" form:"value" json:"value,omitempty" query:"value"` - PlaceholderMessages []*Message `thrift:"placeholder_messages,3,optional" frugal:"3,optional,list" form:"placeholder_messages" json:"placeholder_messages,omitempty" query:"placeholder_messages"` - MultiPartValues []*ContentPart `thrift:"multi_part_values,4,optional" frugal:"4,optional,list" form:"multi_part_values" json:"multi_part_values,omitempty" query:"multi_part_values"` + // 变量key + Key *string `thrift:"key,1,optional" frugal:"1,optional,string" form:"key" json:"key,omitempty" query:"key"` + // 普通变量值(非string类型,如boolean、integer、float、object等,序列化后传入) + Value *string `thrift:"value,2,optional" frugal:"2,optional,string" form:"value" json:"value,omitempty" query:"value"` + // placeholder变量值 + PlaceholderMessages []*Message `thrift:"placeholder_messages,3,optional" frugal:"3,optional,list" form:"placeholder_messages" json:"placeholder_messages,omitempty" query:"placeholder_messages"` + // 多模态变量值 + MultiPartValues []*ContentPart `thrift:"multi_part_values,4,optional" frugal:"4,optional,list" form:"multi_part_values" json:"multi_part_values,omitempty" query:"multi_part_values"` } func NewVariableVal() *VariableVal { @@ -8687,7 +8710,9 @@ func (p *VariableVal) Field4DeepEqual(src []*ContentPart) bool { } type TokenUsage struct { - InputTokens *int32 `thrift:"input_tokens,1,optional" frugal:"1,optional,i32" form:"input_tokens" json:"input_tokens,omitempty" query:"input_tokens"` + // 输入消耗 + InputTokens *int32 `thrift:"input_tokens,1,optional" frugal:"1,optional,i32" form:"input_tokens" json:"input_tokens,omitempty" query:"input_tokens"` + // 输出消耗 OutputTokens *int32 `thrift:"output_tokens,2,optional" frugal:"2,optional,i32" form:"output_tokens" json:"output_tokens,omitempty" query:"output_tokens"` } diff --git a/backend/modules/observability/domain/component/metrics/metrics.go b/backend/modules/observability/domain/component/metrics/metrics.go index 1ebde31f7..f4cba9d42 100644 --- a/backend/modules/observability/domain/component/metrics/metrics.go +++ b/backend/modules/observability/domain/component/metrics/metrics.go @@ -9,5 +9,5 @@ import "time" type ITraceMetrics interface { EmitListSpans(workspaceId int64, spanType string, start time.Time, isError bool) EmitGetTrace(workspaceId int64, start time.Time, isError bool) - EmitTraceOapi(method string, workspaceId int64, platformType, spanType string, spanSize int64, errorCode int, start time.Time, isError bool) + EmitTraceOapi(method string, workspaceId int64, platformType, spanListType string, spanSize int64, errorCode int, start time.Time, isError bool) } diff --git a/backend/modules/observability/domain/component/metrics/mocks/metrics.go b/backend/modules/observability/domain/component/metrics/mocks/metrics.go index 32c1630cb..3bf3770b8 100644 --- a/backend/modules/observability/domain/component/metrics/mocks/metrics.go +++ b/backend/modules/observability/domain/component/metrics/mocks/metrics.go @@ -65,9 +65,9 @@ func (mr *MockITraceMetricsMockRecorder) EmitListSpans(workspaceId, spanType, st } // EmitTraceOapi mocks base method. -func (m *MockITraceMetrics) EmitTraceOapi(method string, workspaceId int64, platformType, spanType string, spanSize int64, errorCode int, start time.Time, isError bool) { +func (m *MockITraceMetrics) EmitTraceOapi(method string, workspaceId int64, platformType, spanListType string, spanSize int64, errorCode int, start time.Time, isError bool) { m.ctrl.T.Helper() - m.ctrl.Call(m, "EmitTraceOapi", method, workspaceId, platformType, spanType, spanSize, errorCode, start, isError) + m.ctrl.Call(m, "EmitTraceOapi", method, workspaceId, platformType, spanListType, spanSize, errorCode, start, isError) } // EmitTraceOapi indicates an expected call of EmitTraceOapi. diff --git a/backend/modules/observability/domain/trace/service/trace/span_filter/cozeloop_filter.go b/backend/modules/observability/domain/trace/service/trace/span_filter/cozeloop_filter.go index e50d4e290..e65229754 100644 --- a/backend/modules/observability/domain/trace/service/trace/span_filter/cozeloop_filter.go +++ b/backend/modules/observability/domain/trace/service/trace/span_filter/cozeloop_filter.go @@ -18,7 +18,7 @@ func (c *CozeLoopFilter) BuildBasicSpanFilter(ctx context.Context, env *SpanEnv) { FieldName: loop_span.SpanFieldSpaceId, FieldType: loop_span.FieldTypeString, - Values: []string{strconv.FormatInt(env.WorkspaceId, 10)}, + Values: []string{strconv.FormatInt(env.WorkspaceID, 10)}, QueryType: ptr.Of(loop_span.QueryTypeEnumIn), }, { diff --git a/backend/modules/observability/domain/trace/service/trace/span_filter/cozeloop_filter_test.go b/backend/modules/observability/domain/trace/service/trace/span_filter/cozeloop_filter_test.go index fee04c1a9..2a379830a 100644 --- a/backend/modules/observability/domain/trace/service/trace/span_filter/cozeloop_filter_test.go +++ b/backend/modules/observability/domain/trace/service/trace/span_filter/cozeloop_filter_test.go @@ -21,7 +21,7 @@ func TestCozeLoopFilter_BuildBasicSpanFilter(t *testing.T) { }{ { name: "success", - env: &SpanEnv{WorkspaceId: 123}, + env: &SpanEnv{WorkspaceID: 123}, want: []*loop_span.FilterField{ { FieldName: loop_span.SpanFieldSpaceId, @@ -56,7 +56,7 @@ func TestCozeLoopFilter_BuildAllSpanFilter(t *testing.T) { }{ { name: "success", - env: &SpanEnv{WorkspaceId: 123}, + env: &SpanEnv{WorkspaceID: 123}, want: nil, }, } @@ -78,7 +78,7 @@ func TestCozeLoopFilter_BuildRootSpanFilter(t *testing.T) { }{ { name: "success", - env: &SpanEnv{WorkspaceId: 123}, + env: &SpanEnv{WorkspaceID: 123}, want: []*loop_span.FilterField{ { FieldName: loop_span.SpanFieldParentID, @@ -107,7 +107,7 @@ func TestCozeLoopFilter_BuildLlmSpanFilter(t *testing.T) { }{ { name: "success", - env: &SpanEnv{WorkspaceId: 123}, + env: &SpanEnv{WorkspaceID: 123}, want: []*loop_span.FilterField{ { FieldName: loop_span.SpanFieldSpanType, diff --git a/backend/modules/observability/domain/trace/service/trace/span_filter/eval_target_filter.go b/backend/modules/observability/domain/trace/service/trace/span_filter/eval_target_filter.go index 6e1af4429..a17ef1ddf 100644 --- a/backend/modules/observability/domain/trace/service/trace/span_filter/eval_target_filter.go +++ b/backend/modules/observability/domain/trace/service/trace/span_filter/eval_target_filter.go @@ -18,7 +18,7 @@ func (e *EvalTargetFilter) BuildBasicSpanFilter(ctx context.Context, env *SpanEn { FieldName: loop_span.SpanFieldSpaceId, FieldType: loop_span.FieldTypeString, - Values: []string{strconv.FormatInt(env.WorkspaceId, 10)}, + Values: []string{strconv.FormatInt(env.WorkspaceID, 10)}, QueryType: ptr.Of(loop_span.QueryTypeEnumIn), }, { diff --git a/backend/modules/observability/domain/trace/service/trace/span_filter/eval_target_filter_test.go b/backend/modules/observability/domain/trace/service/trace/span_filter/eval_target_filter_test.go index afbdc9a03..a3bd5942a 100644 --- a/backend/modules/observability/domain/trace/service/trace/span_filter/eval_target_filter_test.go +++ b/backend/modules/observability/domain/trace/service/trace/span_filter/eval_target_filter_test.go @@ -21,7 +21,7 @@ func TestEvalTargetFilter_BuildBasicSpanFilter(t *testing.T) { }{ { name: "success", - env: &SpanEnv{WorkspaceId: 123}, + env: &SpanEnv{WorkspaceID: 123}, want: []*loop_span.FilterField{ { FieldName: loop_span.SpanFieldSpaceId, @@ -56,7 +56,7 @@ func TestEvalTargetFilter_BuildRootSpanFilter(t *testing.T) { }{ { name: "success", - env: &SpanEnv{WorkspaceId: 123}, + env: &SpanEnv{WorkspaceID: 123}, want: []*loop_span.FilterField{ { FieldName: loop_span.SpanFieldParentID, @@ -85,7 +85,7 @@ func TestEvalTargetFilter_BuildLLMSpanFilter(t *testing.T) { }{ { name: "success", - env: &SpanEnv{WorkspaceId: 123}, + env: &SpanEnv{WorkspaceID: 123}, want: []*loop_span.FilterField{ { FieldName: loop_span.SpanFieldSpanType, @@ -114,7 +114,7 @@ func TestEvalTargetFilter_BuildALLSpanFilter(t *testing.T) { }{ { name: "success", - env: &SpanEnv{WorkspaceId: 123}, + env: &SpanEnv{WorkspaceID: 123}, want: nil, }, } diff --git a/backend/modules/observability/domain/trace/service/trace/span_filter/evaluator_filter.go b/backend/modules/observability/domain/trace/service/trace/span_filter/evaluator_filter.go index bff353e3b..32a4b12d4 100644 --- a/backend/modules/observability/domain/trace/service/trace/span_filter/evaluator_filter.go +++ b/backend/modules/observability/domain/trace/service/trace/span_filter/evaluator_filter.go @@ -18,7 +18,7 @@ func (e *EvaluatorFilter) BuildBasicSpanFilter(ctx context.Context, env *SpanEnv { FieldName: loop_span.SpanFieldSpaceId, FieldType: loop_span.FieldTypeString, - Values: []string{strconv.FormatInt(env.WorkspaceId, 10)}, + Values: []string{strconv.FormatInt(env.WorkspaceID, 10)}, QueryType: ptr.Of(loop_span.QueryTypeEnumIn), }, { diff --git a/backend/modules/observability/domain/trace/service/trace/span_filter/evaluator_filter_test.go b/backend/modules/observability/domain/trace/service/trace/span_filter/evaluator_filter_test.go index 16d9908fa..463ee1873 100644 --- a/backend/modules/observability/domain/trace/service/trace/span_filter/evaluator_filter_test.go +++ b/backend/modules/observability/domain/trace/service/trace/span_filter/evaluator_filter_test.go @@ -21,7 +21,7 @@ func TestEvaluatorFilter_BuildBasicSpanFilter(t *testing.T) { }{ { name: "success", - env: &SpanEnv{WorkspaceId: 123}, + env: &SpanEnv{WorkspaceID: 123}, want: []*loop_span.FilterField{ { FieldName: loop_span.SpanFieldSpaceId, diff --git a/backend/modules/observability/domain/trace/service/trace/span_filter/filter.go b/backend/modules/observability/domain/trace/service/trace/span_filter/filter.go index e1e757abc..5e259a998 100644 --- a/backend/modules/observability/domain/trace/service/trace/span_filter/filter.go +++ b/backend/modules/observability/domain/trace/service/trace/span_filter/filter.go @@ -12,7 +12,7 @@ import ( ) type SpanEnv struct { - WorkspaceId int64 + WorkspaceID int64 ThirdPartyWorkspaceID string } diff --git a/backend/modules/observability/domain/trace/service/trace/span_filter/prompt_filter.go b/backend/modules/observability/domain/trace/service/trace/span_filter/prompt_filter.go index 0aa0350be..37d1bbce7 100644 --- a/backend/modules/observability/domain/trace/service/trace/span_filter/prompt_filter.go +++ b/backend/modules/observability/domain/trace/service/trace/span_filter/prompt_filter.go @@ -22,7 +22,7 @@ func (p *PromptFilter) BuildBasicSpanFilter(ctx context.Context, env *SpanEnv) ( { FieldName: loop_span.SpanFieldSpaceId, FieldType: loop_span.FieldTypeString, - Values: []string{strconv.FormatInt(env.WorkspaceId, 10)}, + Values: []string{strconv.FormatInt(env.WorkspaceID, 10)}, QueryType: ptr.Of(loop_span.QueryTypeEnumIn), }, { diff --git a/backend/modules/observability/domain/trace/service/trace/span_filter/prompt_filter_test.go b/backend/modules/observability/domain/trace/service/trace/span_filter/prompt_filter_test.go index 8eb8ee4a9..452e6211f 100644 --- a/backend/modules/observability/domain/trace/service/trace/span_filter/prompt_filter_test.go +++ b/backend/modules/observability/domain/trace/service/trace/span_filter/prompt_filter_test.go @@ -24,7 +24,7 @@ func TestPromptFilter_BuildBasicSpanFilter(t *testing.T) { }{ { name: "success", - env: &SpanEnv{WorkspaceId: 123}, + env: &SpanEnv{WorkspaceID: 123}, want: []*loop_span.FilterField{ { FieldName: loop_span.SpanFieldSpaceId, diff --git a/backend/modules/observability/domain/trace/service/trace_service.go b/backend/modules/observability/domain/trace/service/trace_service.go index 72c9ce491..b5e235ca7 100644 --- a/backend/modules/observability/domain/trace/service/trace_service.go +++ b/backend/modules/observability/domain/trace/service/trace_service.go @@ -926,7 +926,7 @@ func (r *TraceServiceImpl) getAnnotationCallerCfg(ctx context.Context, caller st func (r *TraceServiceImpl) buildBuiltinFilters(ctx context.Context, f span_filter.Filter, req *ListSpansReq) (*loop_span.FilterFields, error) { filters := make([]*loop_span.FilterField, 0) env := &span_filter.SpanEnv{ - WorkspaceId: req.WorkspaceID, + WorkspaceID: req.WorkspaceID, ThirdPartyWorkspaceID: req.ThirdPartyWorkspaceID, } basicFilter, forceQuery, err := f.BuildBasicSpanFilter(ctx, env) diff --git a/backend/modules/observability/infra/metrics/metrics.go b/backend/modules/observability/infra/metrics/metrics.go index 1f8d790a9..24d72ed62 100644 --- a/backend/modules/observability/infra/metrics/metrics.go +++ b/backend/modules/observability/infra/metrics/metrics.go @@ -29,7 +29,7 @@ const ( tagMethod = "method" tagSpaceID = "workspace_id" tagPlatformType = "platform_type" - tagSpanType = "span_type" + tagSpanType = "span_list_type" tagIsErr = "is_err" tagErrCode = "err_code" ) @@ -102,7 +102,7 @@ func (t *TraceMetricsImpl) EmitGetTrace(workspaceId int64, start time.Time, isEr metrics.Timer(time.Since(start).Microseconds(), metrics.WithSuffix(getTraceSuffix+latencySuffix))) } -func (t *TraceMetricsImpl) EmitTraceOapi(method string, workspaceId int64, platformType, spanType string, spanSize int64, errorCode int, start time.Time, isError bool) { +func (t *TraceMetricsImpl) EmitTraceOapi(method string, workspaceId int64, platformType, spanListType string, spanSize int64, errorCode int, start time.Time, isError bool) { if t.spansMetrics == nil { return } @@ -112,7 +112,7 @@ func (t *TraceMetricsImpl) EmitTraceOapi(method string, workspaceId int64, platf {Name: tagSpaceID, Value: strconv.FormatInt(workspaceId, 10)}, {Name: tagIsErr, Value: strconv.FormatBool(isError)}, {Name: tagPlatformType, Value: platformType}, - {Name: tagSpanType, Value: spanType}, + {Name: tagSpanType, Value: spanListType}, {Name: tagErrCode, Value: strconv.Itoa(errorCode)}, }, metrics.Counter(1, metrics.WithSuffix(traceOApiSuffix+throughputSuffix)), diff --git a/idl/thrift/coze/loop/observability/coze.loop.observability.openapi.thrift b/idl/thrift/coze/loop/observability/coze.loop.observability.openapi.thrift index 58bf8eeca..5126f3560 100644 --- a/idl/thrift/coze/loop/observability/coze.loop.observability.openapi.thrift +++ b/idl/thrift/coze/loop/observability/coze.loop.observability.openapi.thrift @@ -146,7 +146,7 @@ service OpenAPIService { OtelIngestTracesResponse OtelIngestTraces(1: OtelIngestTracesRequest req) (api.post = '/v1/loop/opentelemetry/v1/traces') SearchTraceOApiResponse SearchTraceOApi(1: SearchTraceOApiRequest req) (api.post = '/v1/loop/traces/search') ListSpansOApiResponse ListSpansOApi(1: ListSpansOApiRequest req) (api.post = '/v1/loop/spans/search', api.tag="openapi") - ListTracesOApiResponse ListTracesOApi(1: ListTracesOApiRequest req) (api.post = '/v1/loop/traces/list', api.tag="openapi") + ListTracesOApiResponse ListTracesOApi(1: ListTracesOApiRequest req) (api.post = '/v1/loop/traces/list') CreateAnnotationResponse CreateAnnotation(1: CreateAnnotationRequest req) DeleteAnnotationResponse DeleteAnnotation(1: DeleteAnnotationRequest req) } \ No newline at end of file From 67715c7b03f56770bc201d2233d37f9a72d6cedc Mon Sep 17 00:00:00 2001 From: cuichen Date: Wed, 10 Sep 2025 16:11:16 +0800 Subject: [PATCH 29/29] trace openapi update --- .../observability/application/openapi.go | 6 +- .../observability/application/openapi_test.go | 92 +++++++++---------- .../workspace/mocks/workspace_provider.go | 12 +-- .../domain/component/workspace/workspace.go | 2 +- .../infra/workspace/workspace.go | 2 +- .../infra/workspace/workspace_test.go | 6 +- 6 files changed, 60 insertions(+), 60 deletions(-) diff --git a/backend/modules/observability/application/openapi.go b/backend/modules/observability/application/openapi.go index 050a88664..8ac414d6b 100644 --- a/backend/modules/observability/application/openapi.go +++ b/backend/modules/observability/application/openapi.go @@ -542,7 +542,7 @@ func (o *OpenAPIApplication) buildSearchTraceReq(ctx context.Context, req *opena ret := &service.SearchTraceOApiReq{ WorkspaceID: req.WorkspaceID, - ThirdPartyWorkspaceID: o.workspace.GetQueryWorkSpaceID(ctx, req.WorkspaceID), + ThirdPartyWorkspaceID: o.workspace.GetThirdPartyQueryWorkSpaceID(ctx, req.WorkspaceID), Tenants: o.tenant.GetOAPIQueryTenants(ctx, platformType), TraceID: req.GetTraceID(), LogID: req.GetLogid(), @@ -633,7 +633,7 @@ func (o *OpenAPIApplication) validateListSpansOApi(ctx context.Context, req *ope func (o *OpenAPIApplication) buildListSpansOApiReq(ctx context.Context, req *openapi.ListSpansOApiRequest) (*service.ListSpansOApiReq, error) { ret := &service.ListSpansOApiReq{ WorkspaceID: req.WorkspaceID, - ThirdPartyWorkspaceID: o.workspace.GetQueryWorkSpaceID(ctx, req.WorkspaceID), + ThirdPartyWorkspaceID: o.workspace.GetThirdPartyQueryWorkSpaceID(ctx, req.WorkspaceID), StartTime: req.GetStartTime(), EndTime: req.GetEndTime(), Limit: QueryLimitDefault, @@ -746,7 +746,7 @@ func (o *OpenAPIApplication) validateListTracesOApiReq(ctx context.Context, req func (o *OpenAPIApplication) buildListTracesOApiReq(ctx context.Context, req *openapi.ListTracesOApiRequest) *service.GetTracesAdvanceInfoReq { ret := &service.GetTracesAdvanceInfoReq{ WorkspaceID: req.GetWorkspaceID(), - ThirdPartyWorkspaceID: o.workspace.GetQueryWorkSpaceID(ctx, req.WorkspaceID), + ThirdPartyWorkspaceID: o.workspace.GetThirdPartyQueryWorkSpaceID(ctx, req.WorkspaceID), Traces: make([]*service.TraceQueryParam, len(req.GetTraceIds())), } for i, id := range req.GetTraceIds() { diff --git a/backend/modules/observability/application/openapi_test.go b/backend/modules/observability/application/openapi_test.go index 5436b8b6c..7aed27b68 100644 --- a/backend/modules/observability/application/openapi_test.go +++ b/backend/modules/observability/application/openapi_test.go @@ -206,7 +206,7 @@ func TestOpenAPIApplication_CreateAnnotation(t *testing.T) { authMock := rpcmocks.NewMockIAuthProvider(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -253,7 +253,7 @@ func TestOpenAPIApplication_CreateAnnotation(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -351,7 +351,7 @@ func TestOpenAPIApplication_DeleteAnnotation(t *testing.T) { authMock := rpcmocks.NewMockIAuthProvider(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -443,7 +443,7 @@ func TestOpenAPIApplication_Send(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -539,7 +539,7 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { tenantMock := tenantmocks.NewMockITenantProvider(ctrl) tenantMock.EXPECT().GetIngestTenant(gomock.Any(), gomock.Any()).Return("test-tenant") workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -598,7 +598,7 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { tenantMock := tenantmocks.NewMockITenantProvider(ctrl) tenantMock.EXPECT().GetIngestTenant(gomock.Any(), gomock.Any()).Return("test-tenant") workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -657,7 +657,7 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { tenantMock := tenantmocks.NewMockITenantProvider(ctrl) tenantMock.EXPECT().GetIngestTenant(gomock.Any(), gomock.Any()).Return("test-tenant") workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -712,7 +712,7 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { tenantMock := tenantmocks.NewMockITenantProvider(ctrl) tenantMock.EXPECT().GetIngestTenant(gomock.Any(), gomock.Any()).Return("test-tenant") workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -762,7 +762,7 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -804,7 +804,7 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -851,7 +851,7 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -898,7 +898,7 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -945,7 +945,7 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -992,7 +992,7 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -1040,7 +1040,7 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -1088,7 +1088,7 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -1142,7 +1142,7 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { }, nil) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -1196,7 +1196,7 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { }, nil) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -1252,7 +1252,7 @@ func TestOpenAPIApplication_OtelIngestTraces(t *testing.T) { tenantMock := tenantmocks.NewMockITenantProvider(ctrl) tenantMock.EXPECT().GetIngestTenant(gomock.Any(), gomock.Any()).Return("test-tenant") workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -1477,7 +1477,7 @@ func TestOpenAPIApplication_ListSpansOApi(t *testing.T) { tenantMock := tenantmocks.NewMockITenantProvider(ctrl) tenantMock.EXPECT().GetOAPIQueryTenants(gomock.Any(), gomock.Any()).Return([]string{"tenant1"}) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -1543,7 +1543,7 @@ func TestOpenAPIApplication_ListSpansOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -1601,7 +1601,7 @@ func TestOpenAPIApplication_ListSpansOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -1665,7 +1665,7 @@ func TestOpenAPIApplication_ListSpansOApi(t *testing.T) { traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(100, nil) rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&limiter.Result{Allowed: false}, nil) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -1727,7 +1727,7 @@ func TestOpenAPIApplication_ListSpansOApi(t *testing.T) { traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(100, nil) rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&limiter.Result{Allowed: true}, nil) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -1844,7 +1844,7 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(100, nil) rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&limiter.Result{Allowed: true}, nil) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -1914,7 +1914,7 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(100, nil) rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&limiter.Result{Allowed: true}, nil) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -1972,7 +1972,7 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -2014,7 +2014,7 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -2071,7 +2071,7 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -2130,7 +2130,7 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -2198,7 +2198,7 @@ func TestOpenAPIApplication_SearchTraceOApi(t *testing.T) { traceConfigMock.EXPECT().GetQueryMaxQPS(gomock.Any(), "123").Return(100, nil) rateLimiterFactoryMock.EXPECT().AllowN(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&limiter.Result{Allowed: true}, nil) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -2320,7 +2320,7 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -2391,7 +2391,7 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -2448,7 +2448,7 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -2505,7 +2505,7 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -2563,7 +2563,7 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -2621,7 +2621,7 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -2683,7 +2683,7 @@ func TestOpenAPIApplication_ListTracesOApi(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, spans []*span.InputSpan) string { if len(spans) > 0 { switch spans[0].SpanID { @@ -3088,7 +3088,7 @@ func TestOpenAPIApplication_CreateAnnotation_AdditionalScenarios(t *testing.T) { authMock := rpcmocks.NewMockIAuthProvider(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("").AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() @@ -3129,7 +3129,7 @@ func TestOpenAPIApplication_CreateAnnotation_AdditionalScenarios(t *testing.T) { authMock := rpcmocks.NewMockIAuthProvider(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("").AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() @@ -3166,7 +3166,7 @@ func TestOpenAPIApplication_CreateAnnotation_AdditionalScenarios(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("").AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() @@ -3203,7 +3203,7 @@ func TestOpenAPIApplication_CreateAnnotation_AdditionalScenarios(t *testing.T) { benefitMock := benefitmocks.NewMockIBenefitService(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("").AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() @@ -3241,7 +3241,7 @@ func TestOpenAPIApplication_CreateAnnotation_AdditionalScenarios(t *testing.T) { benefitMock.EXPECT().CheckTraceBenefit(gomock.Any(), gomock.Any()).Return(nil, assert.AnError) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("").AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() @@ -3282,7 +3282,7 @@ func TestOpenAPIApplication_CreateAnnotation_AdditionalScenarios(t *testing.T) { authMock := rpcmocks.NewMockIAuthProvider(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("").AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() @@ -3366,7 +3366,7 @@ func TestOpenAPIApplication_DeleteAnnotation_AdditionalScenarios(t *testing.T) { benefitMock.EXPECT().CheckTraceBenefit(gomock.Any(), gomock.Any()).Return(nil, assert.AnError) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("").AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() @@ -3405,7 +3405,7 @@ func TestOpenAPIApplication_DeleteAnnotation_AdditionalScenarios(t *testing.T) { authMock := rpcmocks.NewMockIAuthProvider(ctrl) tenantMock := tenantmocks.NewMockITenantProvider(ctrl) workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) - workspaceMock.EXPECT().GetQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(123)).Return("123").AnyTimes() workspaceMock.EXPECT().GetIngestWorkSpaceID(gomock.Any(), gomock.Any()).Return("").AnyTimes() rateLimiterMock := limitermocks.NewMockIRateLimiterFactory(ctrl) rateLimiterMock.EXPECT().NewRateLimiter().Return(limitermocks.NewMockIRateLimiter(ctrl)).AnyTimes() diff --git a/backend/modules/observability/domain/component/workspace/mocks/workspace_provider.go b/backend/modules/observability/domain/component/workspace/mocks/workspace_provider.go index f5a063378..3e6496aa5 100644 --- a/backend/modules/observability/domain/component/workspace/mocks/workspace_provider.go +++ b/backend/modules/observability/domain/component/workspace/mocks/workspace_provider.go @@ -55,16 +55,16 @@ func (mr *MockIWorkSpaceProviderMockRecorder) GetIngestWorkSpaceID(ctx, spans an return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetIngestWorkSpaceID", reflect.TypeOf((*MockIWorkSpaceProvider)(nil).GetIngestWorkSpaceID), ctx, spans) } -// GetQueryWorkSpaceID mocks base method. -func (m *MockIWorkSpaceProvider) GetQueryWorkSpaceID(ctx context.Context, requestWorkspaceID int64) string { +// GetThirdPartyQueryWorkSpaceID mocks base method. +func (m *MockIWorkSpaceProvider) GetThirdPartyQueryWorkSpaceID(ctx context.Context, requestWorkspaceID int64) string { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetQueryWorkSpaceID", ctx, requestWorkspaceID) + ret := m.ctrl.Call(m, "GetThirdPartyQueryWorkSpaceID", ctx, requestWorkspaceID) ret0, _ := ret[0].(string) return ret0 } -// GetQueryWorkSpaceID indicates an expected call of GetQueryWorkSpaceID. -func (mr *MockIWorkSpaceProviderMockRecorder) GetQueryWorkSpaceID(ctx, requestWorkspaceID any) *gomock.Call { +// GetThirdPartyQueryWorkSpaceID indicates an expected call of GetThirdPartyQueryWorkSpaceID. +func (mr *MockIWorkSpaceProviderMockRecorder) GetThirdPartyQueryWorkSpaceID(ctx, requestWorkspaceID any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetQueryWorkSpaceID", reflect.TypeOf((*MockIWorkSpaceProvider)(nil).GetQueryWorkSpaceID), ctx, requestWorkspaceID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetThirdPartyQueryWorkSpaceID", reflect.TypeOf((*MockIWorkSpaceProvider)(nil).GetThirdPartyQueryWorkSpaceID), ctx, requestWorkspaceID) } diff --git a/backend/modules/observability/domain/component/workspace/workspace.go b/backend/modules/observability/domain/component/workspace/workspace.go index a4c81da65..b7b539124 100644 --- a/backend/modules/observability/domain/component/workspace/workspace.go +++ b/backend/modules/observability/domain/component/workspace/workspace.go @@ -12,5 +12,5 @@ import ( //go:generate mockgen -destination=mocks/workspace_provider.go -package=mocks . IWorkSpaceProvider type IWorkSpaceProvider interface { GetIngestWorkSpaceID(ctx context.Context, spans []*span.InputSpan) string - GetQueryWorkSpaceID(ctx context.Context, requestWorkspaceID int64) string + GetThirdPartyQueryWorkSpaceID(ctx context.Context, requestWorkspaceID int64) string } diff --git a/backend/modules/observability/infra/workspace/workspace.go b/backend/modules/observability/infra/workspace/workspace.go index ca3e7ae1c..c85eed044 100644 --- a/backend/modules/observability/infra/workspace/workspace.go +++ b/backend/modules/observability/infra/workspace/workspace.go @@ -24,6 +24,6 @@ func (t *WorkspaceProviderImpl) GetIngestWorkSpaceID(ctx context.Context, spans return spans[0].WorkspaceID } -func (t *WorkspaceProviderImpl) GetQueryWorkSpaceID(ctx context.Context, requestWorkspaceID int64) string { +func (t *WorkspaceProviderImpl) GetThirdPartyQueryWorkSpaceID(ctx context.Context, requestWorkspaceID int64) string { return strconv.FormatInt(requestWorkspaceID, 10) } diff --git a/backend/modules/observability/infra/workspace/workspace_test.go b/backend/modules/observability/infra/workspace/workspace_test.go index 50b60a376..f797d2f05 100755 --- a/backend/modules/observability/infra/workspace/workspace_test.go +++ b/backend/modules/observability/infra/workspace/workspace_test.go @@ -135,7 +135,7 @@ func TestWorkspaceProviderImpl_GetQueryWorkSpaceID(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { w := &WorkspaceProviderImpl{} - got := w.GetQueryWorkSpaceID(tt.args.ctx, tt.args.requestWorkspaceID) + got := w.GetThirdPartyQueryWorkSpaceID(tt.args.ctx, tt.args.requestWorkspaceID) assert.Equal(t, tt.want, got) }) } @@ -169,7 +169,7 @@ func TestWorkspaceProviderImpl_Interface(t *testing.T) { assert.NotNil(t, provider) // Test interface methods exist and are callable - workspaceID := provider.GetQueryWorkSpaceID(context.Background(), 123) + workspaceID := provider.GetThirdPartyQueryWorkSpaceID(context.Background(), 123) assert.Equal(t, "123", workspaceID) spans := []*span.InputSpan{{WorkspaceID: "test"}} @@ -182,7 +182,7 @@ func TestWorkspaceProviderImpl_EdgeCases(t *testing.T) { ctx := context.Background() // Test with nil context (should still work) - got := provider.GetQueryWorkSpaceID(ctx, 456) + got := provider.GetThirdPartyQueryWorkSpaceID(ctx, 456) assert.Equal(t, "456", got) // Test with nil context for GetIngestWorkSpaceID