test(ops): 添加告警评估服务单元测试
This commit is contained in:
210
backend/internal/service/ops_alert_evaluator_service_test.go
Normal file
210
backend/internal/service/ops_alert_evaluator_service_test.go
Normal file
@@ -0,0 +1,210 @@
|
||||
//go:build unit
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type stubOpsRepo struct {
|
||||
OpsRepository
|
||||
overview *OpsDashboardOverview
|
||||
err error
|
||||
}
|
||||
|
||||
func (s *stubOpsRepo) GetDashboardOverview(ctx context.Context, filter *OpsDashboardFilter) (*OpsDashboardOverview, error) {
|
||||
if s.err != nil {
|
||||
return nil, s.err
|
||||
}
|
||||
if s.overview != nil {
|
||||
return s.overview, nil
|
||||
}
|
||||
return &OpsDashboardOverview{}, nil
|
||||
}
|
||||
|
||||
func TestComputeGroupAvailableRatio(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("正常情况: 10个账号, 8个可用 = 80%", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got := computeGroupAvailableRatio(&GroupAvailability{
|
||||
TotalAccounts: 10,
|
||||
AvailableCount: 8,
|
||||
})
|
||||
require.InDelta(t, 80.0, got, 0.0001)
|
||||
})
|
||||
|
||||
t.Run("边界情况: TotalAccounts = 0 应返回 0", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got := computeGroupAvailableRatio(&GroupAvailability{
|
||||
TotalAccounts: 0,
|
||||
AvailableCount: 8,
|
||||
})
|
||||
require.Equal(t, 0.0, got)
|
||||
})
|
||||
|
||||
t.Run("边界情况: AvailableCount = 0 应返回 0%", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got := computeGroupAvailableRatio(&GroupAvailability{
|
||||
TotalAccounts: 10,
|
||||
AvailableCount: 0,
|
||||
})
|
||||
require.Equal(t, 0.0, got)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCountAccountsByCondition(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("测试限流账号统计: acc.IsRateLimited", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
accounts := map[int64]*AccountAvailability{
|
||||
1: {IsRateLimited: true},
|
||||
2: {IsRateLimited: false},
|
||||
3: {IsRateLimited: true},
|
||||
}
|
||||
|
||||
got := countAccountsByCondition(accounts, func(acc *AccountAvailability) bool {
|
||||
return acc.IsRateLimited
|
||||
})
|
||||
require.Equal(t, int64(2), got)
|
||||
})
|
||||
|
||||
t.Run("测试错误账号统计(排除临时不可调度): acc.HasError && acc.TempUnschedulableUntil == nil", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
until := time.Now().UTC().Add(5 * time.Minute)
|
||||
accounts := map[int64]*AccountAvailability{
|
||||
1: {HasError: true},
|
||||
2: {HasError: true, TempUnschedulableUntil: &until},
|
||||
3: {HasError: false},
|
||||
}
|
||||
|
||||
got := countAccountsByCondition(accounts, func(acc *AccountAvailability) bool {
|
||||
return acc.HasError && acc.TempUnschedulableUntil == nil
|
||||
})
|
||||
require.Equal(t, int64(1), got)
|
||||
})
|
||||
|
||||
t.Run("边界情况: 空 map 应返回 0", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got := countAccountsByCondition(map[int64]*AccountAvailability{}, func(acc *AccountAvailability) bool {
|
||||
return acc.IsRateLimited
|
||||
})
|
||||
require.Equal(t, int64(0), got)
|
||||
})
|
||||
}
|
||||
|
||||
func TestComputeRuleMetricNewIndicators(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
groupID := int64(101)
|
||||
platform := "openai"
|
||||
|
||||
availability := &OpsAccountAvailability{
|
||||
Group: &GroupAvailability{
|
||||
GroupID: groupID,
|
||||
TotalAccounts: 10,
|
||||
AvailableCount: 8,
|
||||
},
|
||||
Accounts: map[int64]*AccountAvailability{
|
||||
1: {IsRateLimited: true},
|
||||
2: {IsRateLimited: true},
|
||||
3: {HasError: true},
|
||||
4: {HasError: true, TempUnschedulableUntil: timePtr(time.Now().UTC().Add(2 * time.Minute))},
|
||||
5: {HasError: false, IsRateLimited: false},
|
||||
},
|
||||
}
|
||||
|
||||
opsService := &OpsService{
|
||||
getAccountAvailability: func(_ context.Context, _ string, _ *int64) (*OpsAccountAvailability, error) {
|
||||
return availability, nil
|
||||
},
|
||||
}
|
||||
|
||||
svc := &OpsAlertEvaluatorService{
|
||||
opsService: opsService,
|
||||
opsRepo: &stubOpsRepo{overview: &OpsDashboardOverview{}},
|
||||
}
|
||||
|
||||
start := time.Now().UTC().Add(-5 * time.Minute)
|
||||
end := time.Now().UTC()
|
||||
ctx := context.Background()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
metricType string
|
||||
groupID *int64
|
||||
wantValue float64
|
||||
wantOK bool
|
||||
}{
|
||||
{
|
||||
name: "group_available_accounts",
|
||||
metricType: "group_available_accounts",
|
||||
groupID: &groupID,
|
||||
wantValue: 8,
|
||||
wantOK: true,
|
||||
},
|
||||
{
|
||||
name: "group_available_ratio",
|
||||
metricType: "group_available_ratio",
|
||||
groupID: &groupID,
|
||||
wantValue: 80.0,
|
||||
wantOK: true,
|
||||
},
|
||||
{
|
||||
name: "account_rate_limited_count",
|
||||
metricType: "account_rate_limited_count",
|
||||
groupID: nil,
|
||||
wantValue: 2,
|
||||
wantOK: true,
|
||||
},
|
||||
{
|
||||
name: "account_error_count",
|
||||
metricType: "account_error_count",
|
||||
groupID: nil,
|
||||
wantValue: 1,
|
||||
wantOK: true,
|
||||
},
|
||||
{
|
||||
name: "group_available_accounts without group_id returns false",
|
||||
metricType: "group_available_accounts",
|
||||
groupID: nil,
|
||||
wantValue: 0,
|
||||
wantOK: false,
|
||||
},
|
||||
{
|
||||
name: "group_available_ratio without group_id returns false",
|
||||
metricType: "group_available_ratio",
|
||||
groupID: nil,
|
||||
wantValue: 0,
|
||||
wantOK: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rule := &OpsAlertRule{
|
||||
MetricType: tt.metricType,
|
||||
}
|
||||
gotValue, gotOK := svc.computeRuleMetric(ctx, rule, nil, start, end, platform, tt.groupID)
|
||||
require.Equal(t, tt.wantOK, gotOK)
|
||||
if !tt.wantOK {
|
||||
return
|
||||
}
|
||||
require.InDelta(t, tt.wantValue, gotValue, 0.0001)
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user