From 72f548910c52caa6842e76d1776960f78682b4f8 Mon Sep 17 00:00:00 2001 From: cuichen Date: Mon, 2 Mar 2026 15:41:58 +0800 Subject: [PATCH 01/11] MCheckPermission err fix --- backend/modules/observability/infra/rpc/auth/auth.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/modules/observability/infra/rpc/auth/auth.go b/backend/modules/observability/infra/rpc/auth/auth.go index 511df0ab1..0786c34b2 100644 --- a/backend/modules/observability/infra/rpc/auth/auth.go +++ b/backend/modules/observability/infra/rpc/auth/auth.go @@ -53,7 +53,7 @@ func (a *AuthProviderImpl) CheckWorkspacePermission(ctx context.Context, action, } resp, err := a.cli.MCheckPermission(ctx, req) if err != nil { - return errorx.WrapByCode(err, obErrorx.CommercialCommonRPCErrorCodeCode) + return err } else if resp == nil { logs.CtxWarn(ctx, "MCheckPermission returned nil response") return errorx.NewByCode(obErrorx.CommercialCommonRPCErrorCodeCode) From 3c664823dd171ea09e020656d6ab3a0ffd3de918 Mon Sep 17 00:00:00 2001 From: cuichen Date: Mon, 2 Mar 2026 16:21:34 +0800 Subject: [PATCH 02/11] feat: add TimeRangeProvider implementation for OpenAPI search trace request --- .../observability/application/openapi.go | 19 +++++- .../observability/application/openapi_test.go | 58 +++++++++++++++++++ .../modules/observability/application/wire.go | 2 + .../observability/application/wire_gen.go | 6 +- .../time_range/mocks/time_range_mock.go | 55 ++++++++++++++++++ .../domain/component/time_range/time_range.go | 12 ++++ .../infra/time_range/time_range.go | 19 ++++++ 7 files changed, 167 insertions(+), 4 deletions(-) create mode 100644 backend/modules/observability/domain/component/time_range/mocks/time_range_mock.go create mode 100644 backend/modules/observability/domain/component/time_range/time_range.go create mode 100644 backend/modules/observability/infra/time_range/time_range.go diff --git a/backend/modules/observability/application/openapi.go b/backend/modules/observability/application/openapi.go index 461b5630c..7425b760d 100644 --- a/backend/modules/observability/application/openapi.go +++ b/backend/modules/observability/application/openapi.go @@ -18,6 +18,7 @@ import ( "github.com/bytedance/sonic" "github.com/coze-dev/coze-loop/backend/kitex_gen/base" "github.com/coze-dev/coze-loop/backend/modules/observability/domain/component/collector" + "github.com/coze-dev/coze-loop/backend/modules/observability/domain/component/time_range" "github.com/coze-dev/coze-loop/backend/modules/observability/lib/otel" "github.com/coze-dev/coze-loop/backend/pkg/lang/ptr" coltracepb "go.opentelemetry.io/proto/otlp/collector/trace/v1" @@ -66,6 +67,7 @@ func NewOpenAPIApplication( traceConfig config.ITraceConfig, metrics metrics.ITraceMetrics, collector collector.ICollectorProvider, + timeRange time_range.ITimeRangeProvider, ) (IObservabilityOpenAPIApplication, error) { return &OpenAPIApplication{ traceService: traceService, @@ -77,6 +79,7 @@ func NewOpenAPIApplication( traceConfig: traceConfig, metrics: metrics, collector: collector, + timeRange: timeRange, }, nil } @@ -90,6 +93,7 @@ type OpenAPIApplication struct { traceConfig config.ITraceConfig metrics metrics.ITraceMetrics collector collector.ICollectorProvider + timeRange time_range.ITimeRangeProvider } func (o *OpenAPIApplication) IngestTraces(ctx context.Context, req *openapi.IngestTracesRequest) (*openapi.IngestTracesResponse, error) { @@ -574,14 +578,25 @@ func (o *OpenAPIApplication) buildSearchTraceOApiReq(ctx context.Context, req *o platformType = loop_span.PlatformCozeLoop } + startTime := req.GetStartTime() + endTime := req.GetEndTime() + + if startTime == 0 && endTime == 0 { + st, et := o.timeRange.GetTimeRange(ctx, strconv.FormatInt(req.WorkspaceID, 10), req.GetLogid(), req.GetTraceID()) + if st != nil && et != nil { + startTime = *st + endTime = *et + } + } + ret := &service.SearchTraceOApiReq{ WorkspaceID: req.WorkspaceID, ThirdPartyWorkspaceID: o.workspace.GetThirdPartyQueryWorkSpaceID(ctx, req.WorkspaceID), Tenants: o.tenant.GetOAPIQueryTenants(ctx, platformType), TraceID: req.GetTraceID(), LogID: req.GetLogid(), - StartTime: req.GetStartTime(), - EndTime: req.GetEndTime(), + StartTime: startTime, + EndTime: endTime, Limit: req.GetLimit(), PlatformType: platformType, WithDetail: true, diff --git a/backend/modules/observability/application/openapi_test.go b/backend/modules/observability/application/openapi_test.go index 691e3f7ec..10c7ac978 100755 --- a/backend/modules/observability/application/openapi_test.go +++ b/backend/modules/observability/application/openapi_test.go @@ -30,6 +30,7 @@ import ( rpcmocks "github.com/coze-dev/coze-loop/backend/modules/observability/domain/component/rpc/mocks" "github.com/coze-dev/coze-loop/backend/modules/observability/domain/component/tenant" tenantmocks "github.com/coze-dev/coze-loop/backend/modules/observability/domain/component/tenant/mocks" + time_rangemocks "github.com/coze-dev/coze-loop/backend/modules/observability/domain/component/time_range/mocks" "github.com/coze-dev/coze-loop/backend/modules/observability/domain/component/workspace" workspacemocks "github.com/coze-dev/coze-loop/backend/modules/observability/domain/component/workspace/mocks" "github.com/coze-dev/coze-loop/backend/modules/observability/domain/trace/entity" @@ -964,6 +965,7 @@ func TestNewOpenAPIApplication(t *testing.T) { traceConfigMock := configmocks.NewMockITraceConfig(ctrl) metricsMock := metricsmocks.NewMockITraceMetrics(ctrl) collectorMock := collectormocks.NewMockICollectorProvider(ctrl) + timeRangeMock := time_rangemocks.NewMockITimeRangeProvider(ctrl) rateLimiterFactoryMock.EXPECT().NewRateLimiter().Return(rateLimiterMock) @@ -977,6 +979,7 @@ func TestNewOpenAPIApplication(t *testing.T) { traceConfigMock, metricsMock, collectorMock, + timeRangeMock, ) assert.NoError(t, err) @@ -994,6 +997,7 @@ func TestNewOpenAPIApplication(t *testing.T) { assert.NotNil(t, openAPIApp.traceConfig) assert.NotNil(t, openAPIApp.metrics) assert.NotNil(t, openAPIApp.collector) + assert.NotNil(t, openAPIApp.timeRange) } // 补充IngestTraces的边界测试场景 @@ -2797,3 +2801,57 @@ func TestUngzip(t *testing.T) { assert.Nil(t, result) }) } + +func TestOpenAPIApplication_buildSearchTraceOApiReq_TimeRangeFallback(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + tenantMock := tenantmocks.NewMockITenantProvider(ctrl) + workspaceMock := workspacemocks.NewMockIWorkSpaceProvider(ctrl) + timeRangeMock := time_rangemocks.NewMockITimeRangeProvider(ctrl) + + app := &OpenAPIApplication{ + tenant: tenantMock, + workspace: workspaceMock, + timeRange: timeRangeMock, + } + + ctx := context.Background() + + // Case: StartTime=0, EndTime=0 -> use TimeRangeProvider + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(1)).Return("third-1") + tenantMock.EXPECT().GetOAPIQueryTenants(gomock.Any(), loop_span.PlatformCozeLoop).Return([]string{"tenant-a"}) + + start := int64(1000) + end := int64(2000) + timeRangeMock.EXPECT().GetTimeRange(gomock.Any(), "1", "log-id", "trace-id").Return(&start, &end) + + req := &openapi.SearchTraceOApiRequest{ + WorkspaceID: 1, + TraceID: ptr.Of("trace-id"), + Logid: ptr.Of("log-id"), + StartTime: 0, + EndTime: 0, + Limit: 50, + } + + res, err := app.buildSearchTraceOApiReq(ctx, req) + assert.NoError(t, err) + assert.Equal(t, start, res.StartTime) + assert.Equal(t, end, res.EndTime) + + // Case: StartTime=0, EndTime=0 -> TimeRangeProvider returns nil -> use 0 + workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(2)).Return("third-2") + tenantMock.EXPECT().GetOAPIQueryTenants(gomock.Any(), loop_span.PlatformCozeLoop).Return([]string{"tenant-b"}) + timeRangeMock.EXPECT().GetTimeRange(gomock.Any(), "2", "", "").Return(nil, nil) + + req2 := &openapi.SearchTraceOApiRequest{ + WorkspaceID: 2, + StartTime: 0, + EndTime: 0, + } + res2, err := app.buildSearchTraceOApiReq(ctx, req2) + assert.NoError(t, err) + assert.Equal(t, int64(0), res2.StartTime) + assert.Equal(t, int64(0), res2.EndTime) +} diff --git a/backend/modules/observability/application/wire.go b/backend/modules/observability/application/wire.go index f66351cc0..39f6cda88 100644 --- a/backend/modules/observability/application/wire.go +++ b/backend/modules/observability/application/wire.go @@ -73,6 +73,7 @@ import ( "github.com/coze-dev/coze-loop/backend/modules/observability/infra/rpc/user" obstorage "github.com/coze-dev/coze-loop/backend/modules/observability/infra/storage" "github.com/coze-dev/coze-loop/backend/modules/observability/infra/tenant" + "github.com/coze-dev/coze-loop/backend/modules/observability/infra/time_range" "github.com/coze-dev/coze-loop/backend/modules/observability/infra/workspace" "github.com/coze-dev/coze-loop/backend/pkg/conf" "github.com/google/wire" @@ -137,6 +138,7 @@ var ( NewOpenAPIApplication, auth.NewAuthProvider, traceDomainSet, + time_range.NewTimeRangeProvider, ) taskSet = wire.NewSet( tracehub.NewTraceHubImpl, diff --git a/backend/modules/observability/application/wire_gen.go b/backend/modules/observability/application/wire_gen.go index 22dc1b3ae..6cb5f93f3 100644 --- a/backend/modules/observability/application/wire_gen.go +++ b/backend/modules/observability/application/wire_gen.go @@ -73,6 +73,7 @@ import ( "github.com/coze-dev/coze-loop/backend/modules/observability/infra/rpc/user" "github.com/coze-dev/coze-loop/backend/modules/observability/infra/storage" "github.com/coze-dev/coze-loop/backend/modules/observability/infra/tenant" + "github.com/coze-dev/coze-loop/backend/modules/observability/infra/time_range" "github.com/coze-dev/coze-loop/backend/modules/observability/infra/workspace" "github.com/coze-dev/coze-loop/backend/pkg/conf" "github.com/google/wire" @@ -184,7 +185,8 @@ func InitOpenAPIApplication(mqFactory mq.IFactory, configFactory conf.IConfigLoa iAuthProvider := auth.NewAuthProvider(authClient) iWorkSpaceProvider := workspace.NewWorkspaceProvider() iCollectorProvider := collector.NewEventCollectorProvider() - iObservabilityOpenAPIApplication, err := NewOpenAPIApplication(iTraceService, iAuthProvider, benefit2, iTenantProvider, iWorkSpaceProvider, limiterFactory, iTraceConfig, iTraceMetrics, iCollectorProvider) + iTimeRangeProvider := time_range.NewTimeRangeProvider() + iObservabilityOpenAPIApplication, err := NewOpenAPIApplication(iTraceService, iAuthProvider, benefit2, iTenantProvider, iWorkSpaceProvider, limiterFactory, iTraceConfig, iTraceMetrics, iCollectorProvider, iTimeRangeProvider) if err != nil { return nil, err } @@ -339,7 +341,7 @@ var ( NewIngestionCollectorFactory, producer.NewSpanWithAnnotationProducerImpl, redis2.NewSpansRedisDaoImpl, mysql.NewTrajectoryConfigDaoImpl, ) openApiSet = wire.NewSet( - NewOpenAPIApplication, auth.NewAuthProvider, traceDomainSet, + NewOpenAPIApplication, auth.NewAuthProvider, traceDomainSet, time_range.NewTimeRangeProvider, ) taskSet = wire.NewSet(tracehub.NewTraceHubImpl, NewTaskApplication, auth.NewAuthProvider, user.NewUserRPCProvider, evaluation.NewEvaluationRPCProvider, NewTaskLocker, traceDomainSet, service3.NewTaskCallbackServiceImpl, diff --git a/backend/modules/observability/domain/component/time_range/mocks/time_range_mock.go b/backend/modules/observability/domain/component/time_range/mocks/time_range_mock.go new file mode 100644 index 000000000..85beab84d --- /dev/null +++ b/backend/modules/observability/domain/component/time_range/mocks/time_range_mock.go @@ -0,0 +1,55 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/coze-dev/coze-loop/backend/modules/observability/domain/component/time_range (interfaces: ITimeRangeProvider) +// +// Generated by this command: +// +// mockgen -destination=modules/observability/domain/component/time_range/mocks/time_range_mock.go -package=mocks github.com/coze-dev/coze-loop/backend/modules/observability/domain/component/time_range ITimeRangeProvider +// + +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + reflect "reflect" + + gomock "go.uber.org/mock/gomock" +) + +// MockITimeRangeProvider is a mock of ITimeRangeProvider interface. +type MockITimeRangeProvider struct { + ctrl *gomock.Controller + recorder *MockITimeRangeProviderMockRecorder +} + +// MockITimeRangeProviderMockRecorder is the mock recorder for MockITimeRangeProvider. +type MockITimeRangeProviderMockRecorder struct { + mock *MockITimeRangeProvider +} + +// NewMockITimeRangeProvider creates a new mock instance. +func NewMockITimeRangeProvider(ctrl *gomock.Controller) *MockITimeRangeProvider { + mock := &MockITimeRangeProvider{ctrl: ctrl} + mock.recorder = &MockITimeRangeProviderMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockITimeRangeProvider) EXPECT() *MockITimeRangeProviderMockRecorder { + return m.recorder +} + +// GetTimeRange mocks base method. +func (m *MockITimeRangeProvider) GetTimeRange(arg0 context.Context, arg1, arg2, arg3 string) (*int64, *int64) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTimeRange", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*int64) + ret1, _ := ret[1].(*int64) + return ret0, ret1 +} + +// GetTimeRange indicates an expected call of GetTimeRange. +func (mr *MockITimeRangeProviderMockRecorder) GetTimeRange(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTimeRange", reflect.TypeOf((*MockITimeRangeProvider)(nil).GetTimeRange), arg0, arg1, arg2, arg3) +} diff --git a/backend/modules/observability/domain/component/time_range/time_range.go b/backend/modules/observability/domain/component/time_range/time_range.go new file mode 100644 index 000000000..f8ef9bf10 --- /dev/null +++ b/backend/modules/observability/domain/component/time_range/time_range.go @@ -0,0 +1,12 @@ +// Copyright (c) 2026 coze-dev Authors +// SPDX-License-Identifier: Apache-2.0 +package time_range + +import ( + "context" +) + +//go:generate mockgen -destination=mocks/time_range_mock.go -package=mocks . ITimeRangeProvider +type ITimeRangeProvider interface { + GetTimeRange(ctx context.Context, workSpaceID, logID, traceID string) (*int64, *int64) +} diff --git a/backend/modules/observability/infra/time_range/time_range.go b/backend/modules/observability/infra/time_range/time_range.go new file mode 100644 index 000000000..08a7bc214 --- /dev/null +++ b/backend/modules/observability/infra/time_range/time_range.go @@ -0,0 +1,19 @@ +// Copyright (c) 2026 coze-dev Authors +// SPDX-License-Identifier: Apache-2.0 +package time_range + +import ( + "context" + + "github.com/coze-dev/coze-loop/backend/modules/observability/domain/component/time_range" +) + +type TimeRangeProvider struct{} + +func NewTimeRangeProvider() time_range.ITimeRangeProvider { + return &TimeRangeProvider{} +} + +func (p *TimeRangeProvider) GetTimeRange(ctx context.Context, workSpaceID, logID, traceID string) (*int64, *int64) { + return nil, nil +} From 9545c08a6341a63bda744d775d7f03ca897d2338 Mon Sep 17 00:00:00 2001 From: cuichen Date: Mon, 2 Mar 2026 16:33:01 +0800 Subject: [PATCH 03/11] fix: gofmt for openapi_test.go --- .../observability/application/openapi_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/modules/observability/application/openapi_test.go b/backend/modules/observability/application/openapi_test.go index 10c7ac978..bddf21c25 100755 --- a/backend/modules/observability/application/openapi_test.go +++ b/backend/modules/observability/application/openapi_test.go @@ -2827,12 +2827,12 @@ func TestOpenAPIApplication_buildSearchTraceOApiReq_TimeRangeFallback(t *testing timeRangeMock.EXPECT().GetTimeRange(gomock.Any(), "1", "log-id", "trace-id").Return(&start, &end) req := &openapi.SearchTraceOApiRequest{ - WorkspaceID: 1, - TraceID: ptr.Of("trace-id"), - Logid: ptr.Of("log-id"), - StartTime: 0, - EndTime: 0, - Limit: 50, + WorkspaceID: 1, + TraceID: ptr.Of("trace-id"), + Logid: ptr.Of("log-id"), + StartTime: 0, + EndTime: 0, + Limit: 50, } res, err := app.buildSearchTraceOApiReq(ctx, req) From af2106b5af8a52d0f25bfcfff58071ddb30e5393 Mon Sep 17 00:00:00 2001 From: cuichen Date: Mon, 2 Mar 2026 17:19:50 +0800 Subject: [PATCH 04/11] fix: update TestAuthProviderImpl_CheckWorkspacePermission to expect raw error --- backend/modules/observability/infra/rpc/auth/auth_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/modules/observability/infra/rpc/auth/auth_test.go b/backend/modules/observability/infra/rpc/auth/auth_test.go index 49e1e552f..0281c5288 100644 --- a/backend/modules/observability/infra/rpc/auth/auth_test.go +++ b/backend/modules/observability/infra/rpc/auth/auth_test.go @@ -98,7 +98,7 @@ func TestAuthProviderImpl_CheckWorkspacePermission(t *testing.T) { mockClient.EXPECT().MCheckPermission(gomock.Any(), gomock.Any()).Return(nil, errors.New("RPC error")) }, wantErr: true, - expectedErr: obErrorx.CommercialCommonRPCErrorCodeCode, + expectedErr: 0, }, { name: "nil response", From bf0e22fdc283129a030aa89cae90f73203a5f9ba Mon Sep 17 00:00:00 2001 From: cuichen Date: Mon, 2 Mar 2026 17:50:00 +0800 Subject: [PATCH 05/11] test: add unit tests for TimeRangeProvider --- .../infra/time_range/time_range_test.go | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 backend/modules/observability/infra/time_range/time_range_test.go diff --git a/backend/modules/observability/infra/time_range/time_range_test.go b/backend/modules/observability/infra/time_range/time_range_test.go new file mode 100644 index 000000000..a0385aa38 --- /dev/null +++ b/backend/modules/observability/infra/time_range/time_range_test.go @@ -0,0 +1,27 @@ +// Copyright (c) 2026 coze-dev Authors +// SPDX-License-Identifier: Apache-2.0 +package time_range + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewTimeRangeProvider(t *testing.T) { + provider := NewTimeRangeProvider() + assert.NotNil(t, provider) + assert.IsType(t, &TimeRangeProvider{}, provider) +} + +func TestTimeRangeProvider_GetTimeRange(t *testing.T) { + provider := NewTimeRangeProvider() + ctx := context.Background() + + t.Run("returns nil for any input", func(t *testing.T) { + start, end := provider.GetTimeRange(ctx, "workspace1", "log1", "trace1") + assert.Nil(t, start) + assert.Nil(t, end) + }) +} From 53981f86219185a2840a2806754a8a76c7d09307 Mon Sep 17 00:00:00 2001 From: cuichen Date: Mon, 2 Mar 2026 20:39:10 +0800 Subject: [PATCH 06/11] test: update TestOpenAPIApplication_buildSearchTraceOApiReq_TimeRangeFallback to expect no error for zero time --- .../modules/observability/application/openapi_test.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/backend/modules/observability/application/openapi_test.go b/backend/modules/observability/application/openapi_test.go index bddf21c25..3426a7166 100755 --- a/backend/modules/observability/application/openapi_test.go +++ b/backend/modules/observability/application/openapi_test.go @@ -2822,8 +2822,9 @@ func TestOpenAPIApplication_buildSearchTraceOApiReq_TimeRangeFallback(t *testing workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(1)).Return("third-1") tenantMock.EXPECT().GetOAPIQueryTenants(gomock.Any(), loop_span.PlatformCozeLoop).Return([]string{"tenant-a"}) - start := int64(1000) - end := int64(2000) + now := time.Now().UnixMilli() + start := now - 10000 + end := now timeRangeMock.EXPECT().GetTimeRange(gomock.Any(), "1", "log-id", "trace-id").Return(&start, &end) req := &openapi.SearchTraceOApiRequest{ @@ -2837,8 +2838,10 @@ func TestOpenAPIApplication_buildSearchTraceOApiReq_TimeRangeFallback(t *testing res, err := app.buildSearchTraceOApiReq(ctx, req) assert.NoError(t, err) - assert.Equal(t, start, res.StartTime) - assert.Equal(t, end, res.EndTime) + if assert.NotNil(t, res) { + assert.Equal(t, start, res.StartTime) + assert.Equal(t, end, res.EndTime) + } // Case: StartTime=0, EndTime=0 -> TimeRangeProvider returns nil -> use 0 workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(2)).Return("third-2") From 056f821659914ba84e21ba2e804df1a2de86fd7d Mon Sep 17 00:00:00 2001 From: cuichen Date: Mon, 2 Mar 2026 20:41:28 +0800 Subject: [PATCH 07/11] fix --- .../observability/application/openapi.go | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/backend/modules/observability/application/openapi.go b/backend/modules/observability/application/openapi.go index 7425b760d..ef7826979 100644 --- a/backend/modules/observability/application/openapi.go +++ b/backend/modules/observability/application/openapi.go @@ -558,17 +558,7 @@ func (o *OpenAPIApplication) validateSearchTraceOApiReq(ctx context.Context, req } else if req.Limit > MaxListSpansLimit || req.Limit < 0 { return errorx.NewByCode(obErrorx.CommercialCommonInvalidParamCodeCode, errorx.WithExtraMsg("invalid limit")) } - v := utils.DateValidator{ - Start: req.GetStartTime(), - End: req.GetEndTime(), - EarliestDays: 365, - } - newStartTime, newEndTime, err := v.CorrectDate() - if err != nil { - return err - } - req.SetStartTime(newStartTime) - req.SetEndTime(newEndTime) + return nil } @@ -589,14 +579,24 @@ func (o *OpenAPIApplication) buildSearchTraceOApiReq(ctx context.Context, req *o } } + v := utils.DateValidator{ + Start: startTime, + End: endTime, + EarliestDays: 365, + } + newStartTime, newEndTime, err := v.CorrectDate() + if err != nil { + return nil, err + } + ret := &service.SearchTraceOApiReq{ WorkspaceID: req.WorkspaceID, ThirdPartyWorkspaceID: o.workspace.GetThirdPartyQueryWorkSpaceID(ctx, req.WorkspaceID), Tenants: o.tenant.GetOAPIQueryTenants(ctx, platformType), TraceID: req.GetTraceID(), LogID: req.GetLogid(), - StartTime: startTime, - EndTime: endTime, + StartTime: newStartTime, + EndTime: newEndTime, Limit: req.GetLimit(), PlatformType: platformType, WithDetail: true, From 09d45cc21451fa86eaa6daeb07ae639ed0add376 Mon Sep 17 00:00:00 2001 From: cuichen Date: Mon, 2 Mar 2026 20:42:43 +0800 Subject: [PATCH 08/11] test: update TestOpenAPIApplication_buildSearchTraceOApiReq_TimeRangeFallback to expect error for zero time --- .../modules/observability/application/openapi_test.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/backend/modules/observability/application/openapi_test.go b/backend/modules/observability/application/openapi_test.go index 3426a7166..dd96aea56 100755 --- a/backend/modules/observability/application/openapi_test.go +++ b/backend/modules/observability/application/openapi_test.go @@ -2843,9 +2843,7 @@ func TestOpenAPIApplication_buildSearchTraceOApiReq_TimeRangeFallback(t *testing assert.Equal(t, end, res.EndTime) } - // Case: StartTime=0, EndTime=0 -> TimeRangeProvider returns nil -> use 0 - workspaceMock.EXPECT().GetThirdPartyQueryWorkSpaceID(gomock.Any(), int64(2)).Return("third-2") - tenantMock.EXPECT().GetOAPIQueryTenants(gomock.Any(), loop_span.PlatformCozeLoop).Return([]string{"tenant-b"}) + // Case: StartTime=0, EndTime=0 -> TimeRangeProvider returns nil -> should return error because DateValidator requires non-zero time timeRangeMock.EXPECT().GetTimeRange(gomock.Any(), "2", "", "").Return(nil, nil) req2 := &openapi.SearchTraceOApiRequest{ @@ -2854,7 +2852,6 @@ func TestOpenAPIApplication_buildSearchTraceOApiReq_TimeRangeFallback(t *testing EndTime: 0, } res2, err := app.buildSearchTraceOApiReq(ctx, req2) - assert.NoError(t, err) - assert.Equal(t, int64(0), res2.StartTime) - assert.Equal(t, int64(0), res2.EndTime) + assert.Error(t, err) + assert.Nil(t, res2) } From 97d3dc15b04f2c3266410b8b37f10817f3743bcb Mon Sep 17 00:00:00 2001 From: cuichen Date: Mon, 2 Mar 2026 20:45:58 +0800 Subject: [PATCH 09/11] fix: remove invalid time validation tests from TestOpenAPIApplication_validateSearchTraceOApiReq --- .../modules/observability/application/openapi_test.go | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/backend/modules/observability/application/openapi_test.go b/backend/modules/observability/application/openapi_test.go index dd96aea56..22eb76484 100755 --- a/backend/modules/observability/application/openapi_test.go +++ b/backend/modules/observability/application/openapi_test.go @@ -2017,19 +2017,8 @@ func TestOpenAPIApplication_validateSearchTraceOApiReq(t *testing.T) { negativeLimit.Limit = -1 assert.Error(t, app.validateSearchTraceOApiReq(ctx, &negativeLimit)) - // invalid time range (zero values) - invalidTime := *validReq - invalidTime.StartTime = 0 - invalidTime.EndTime = 0 - assert.Error(t, app.validateSearchTraceOApiReq(ctx, &invalidTime)) - // valid request should pass assert.NoError(t, app.validateSearchTraceOApiReq(ctx, validReq)) - - // start time later than end time - invalidRange := *validReq - invalidRange.StartTime = now + 1000 - assert.Error(t, app.validateSearchTraceOApiReq(ctx, &invalidRange)) } func TestOpenAPIApplication_buildSearchTraceOApiReq(t *testing.T) { From eaa92a9afa319fbc22cc5a541847c30b230ecdec Mon Sep 17 00:00:00 2001 From: cuichen Date: Tue, 3 Mar 2026 20:10:53 +0800 Subject: [PATCH 10/11] update --- backend/modules/observability/application/openapi.go | 2 +- .../component/time_range/mocks/time_range_mock.go | 11 ++++++----- .../domain/component/time_range/time_range.go | 2 +- .../observability/infra/time_range/time_range.go | 2 +- .../observability/infra/time_range/time_range_test.go | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/backend/modules/observability/application/openapi.go b/backend/modules/observability/application/openapi.go index 7b1aeb6d0..04360b615 100644 --- a/backend/modules/observability/application/openapi.go +++ b/backend/modules/observability/application/openapi.go @@ -576,7 +576,7 @@ func (o *OpenAPIApplication) buildSearchTraceOApiReq(ctx context.Context, req *o endTime := req.GetEndTime() if startTime == 0 && endTime == 0 { - st, et := o.timeRange.GetTimeRange(ctx, strconv.FormatInt(req.WorkspaceID, 10), req.GetLogid(), req.GetTraceID()) + st, et := o.timeRange.GetTimeRange(ctx, strconv.FormatInt(req.WorkspaceID, 10), req.GetLogid(), req.GetTraceID(), 1000*60*60*24) if st != nil && et != nil { startTime = *st endTime = *et diff --git a/backend/modules/observability/domain/component/time_range/mocks/time_range_mock.go b/backend/modules/observability/domain/component/time_range/mocks/time_range_mock.go index 85beab84d..9a55d9b35 100644 --- a/backend/modules/observability/domain/component/time_range/mocks/time_range_mock.go +++ b/backend/modules/observability/domain/component/time_range/mocks/time_range_mock.go @@ -3,7 +3,7 @@ // // Generated by this command: // -// mockgen -destination=modules/observability/domain/component/time_range/mocks/time_range_mock.go -package=mocks github.com/coze-dev/coze-loop/backend/modules/observability/domain/component/time_range ITimeRangeProvider +// mockgen -destination=mocks/time_range_mock.go -package=mocks . ITimeRangeProvider // // Package mocks is a generated GoMock package. @@ -20,6 +20,7 @@ import ( type MockITimeRangeProvider struct { ctrl *gomock.Controller recorder *MockITimeRangeProviderMockRecorder + isgomock struct{} } // MockITimeRangeProviderMockRecorder is the mock recorder for MockITimeRangeProvider. @@ -40,16 +41,16 @@ func (m *MockITimeRangeProvider) EXPECT() *MockITimeRangeProviderMockRecorder { } // GetTimeRange mocks base method. -func (m *MockITimeRangeProvider) GetTimeRange(arg0 context.Context, arg1, arg2, arg3 string) (*int64, *int64) { +func (m *MockITimeRangeProvider) GetTimeRange(ctx context.Context, workSpaceID, logID, traceID string, delayTime int64) (*int64, *int64) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetTimeRange", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "GetTimeRange", ctx, workSpaceID, logID, traceID, delayTime) ret0, _ := ret[0].(*int64) ret1, _ := ret[1].(*int64) return ret0, ret1 } // GetTimeRange indicates an expected call of GetTimeRange. -func (mr *MockITimeRangeProviderMockRecorder) GetTimeRange(arg0, arg1, arg2, arg3 any) *gomock.Call { +func (mr *MockITimeRangeProviderMockRecorder) GetTimeRange(ctx, workSpaceID, logID, traceID, delayTime any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTimeRange", reflect.TypeOf((*MockITimeRangeProvider)(nil).GetTimeRange), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTimeRange", reflect.TypeOf((*MockITimeRangeProvider)(nil).GetTimeRange), ctx, workSpaceID, logID, traceID, delayTime) } diff --git a/backend/modules/observability/domain/component/time_range/time_range.go b/backend/modules/observability/domain/component/time_range/time_range.go index f8ef9bf10..c87a69aea 100644 --- a/backend/modules/observability/domain/component/time_range/time_range.go +++ b/backend/modules/observability/domain/component/time_range/time_range.go @@ -8,5 +8,5 @@ import ( //go:generate mockgen -destination=mocks/time_range_mock.go -package=mocks . ITimeRangeProvider type ITimeRangeProvider interface { - GetTimeRange(ctx context.Context, workSpaceID, logID, traceID string) (*int64, *int64) + GetTimeRange(ctx context.Context, workSpaceID, logID, traceID string, delayTime int64) (*int64, *int64) } diff --git a/backend/modules/observability/infra/time_range/time_range.go b/backend/modules/observability/infra/time_range/time_range.go index 08a7bc214..65711c577 100644 --- a/backend/modules/observability/infra/time_range/time_range.go +++ b/backend/modules/observability/infra/time_range/time_range.go @@ -14,6 +14,6 @@ func NewTimeRangeProvider() time_range.ITimeRangeProvider { return &TimeRangeProvider{} } -func (p *TimeRangeProvider) GetTimeRange(ctx context.Context, workSpaceID, logID, traceID string) (*int64, *int64) { +func (p *TimeRangeProvider) GetTimeRange(ctx context.Context, workSpaceID, logID, traceID string, delayTime int64) (*int64, *int64) { return nil, nil } diff --git a/backend/modules/observability/infra/time_range/time_range_test.go b/backend/modules/observability/infra/time_range/time_range_test.go index a0385aa38..ff5eaabf8 100644 --- a/backend/modules/observability/infra/time_range/time_range_test.go +++ b/backend/modules/observability/infra/time_range/time_range_test.go @@ -20,7 +20,7 @@ func TestTimeRangeProvider_GetTimeRange(t *testing.T) { ctx := context.Background() t.Run("returns nil for any input", func(t *testing.T) { - start, end := provider.GetTimeRange(ctx, "workspace1", "log1", "trace1") + start, end := provider.GetTimeRange(ctx, "workspace1", "log1", "trace1", 0) assert.Nil(t, start) assert.Nil(t, end) }) From 6b8282416a127a582eb81033559bfe5925c6747c Mon Sep 17 00:00:00 2001 From: cuichen Date: Tue, 3 Mar 2026 20:38:56 +0800 Subject: [PATCH 11/11] fix: update GetTimeRange mock calls with delayTime parameter --- 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 31200386d..ddcbf54ca 100755 --- a/backend/modules/observability/application/openapi_test.go +++ b/backend/modules/observability/application/openapi_test.go @@ -2825,7 +2825,7 @@ func TestOpenAPIApplication_buildSearchTraceOApiReq_TimeRangeFallback(t *testing now := time.Now().UnixMilli() start := now - 10000 end := now - timeRangeMock.EXPECT().GetTimeRange(gomock.Any(), "1", "log-id", "trace-id").Return(&start, &end) + timeRangeMock.EXPECT().GetTimeRange(gomock.Any(), "1", "log-id", "trace-id", gomock.Any()).Return(&start, &end) req := &openapi.SearchTraceOApiRequest{ WorkspaceID: 1, @@ -2844,7 +2844,7 @@ func TestOpenAPIApplication_buildSearchTraceOApiReq_TimeRangeFallback(t *testing } // Case: StartTime=0, EndTime=0 -> TimeRangeProvider returns nil -> should return error because DateValidator requires non-zero time - timeRangeMock.EXPECT().GetTimeRange(gomock.Any(), "2", "", "").Return(nil, nil) + timeRangeMock.EXPECT().GetTimeRange(gomock.Any(), "2", "", "", gomock.Any()).Return(nil, nil) req2 := &openapi.SearchTraceOApiRequest{ WorkspaceID: 2,