211 lines
4.8 KiB
Go
211 lines
4.8 KiB
Go
//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)
|
|
})
|
|
}
|
|
}
|