test(billing): tighten DeepSeek V4 fallback assertions; clarify branch comments

Address copilot-pull-request-reviewer feedback on #2157:

- billing_service_test.go: extend TestGetFallbackPricing_FamilyMatching
  with optional expectedOutput / expectedCacheRead fields and assert
  full Input/Output/CacheRead pricing for all 4 DeepSeek cases
  (v4-pro, v4-flash, deepseek-chat→flash, deepseek-reasoner→flash),
  preventing silent regression to 0 output/cache cost.
- billing_service.go: rewrite the DeepSeek block comment to explicitly
  describe its scope (V4 Pro/Flash + chat/reasoner aliases, no
  unknown-deepseek fallback) and tighten the OpenAI comment to make
  it unambiguous that it only describes the OpenAI/Codex branch
  immediately below it.
This commit is contained in:
alfadb
2026-06-16 19:37:02 +08:00
parent 27e26a3a90
commit 5a593a511e
2 changed files with 46 additions and 11 deletions
+3 -3
View File
@@ -362,19 +362,19 @@ func (s *BillingService) getFallbackPricing(model string) *ModelPricing {
return s.fallbackPrices["gemini-3.1-pro"]
}
// DeepSeek V4 系列
// DeepSeek V4 系列:仅匹配已知 V4 Pro/Flash 与官方兼容别名
// (deepseek-chat / deepseek-reasoner → V4 Flash),未知 deepseek-* 型号不回退,避免误计价。
if strings.Contains(modelLower, "deepseek-v4-flash") {
return s.fallbackPrices["deepseek-v4-flash"]
}
if strings.Contains(modelLower, "deepseek-v4-pro") {
return s.fallbackPrices["deepseek-v4-pro"]
}
// deepseek-chat / deepseek-reasoner → V4 Flash(官方兼容别名)
if strings.Contains(modelLower, "deepseek-chat") || strings.Contains(modelLower, "deepseek-reasoner") {
return s.fallbackPrices["deepseek-v4-flash"]
}
// OpenAI 仅匹配已知 GPT-5/Codex 族,避免未知 OpenAI 型号误计价。
// OpenAI(GPT-5 / Codex 族):仅匹配已知型号,避免未知 OpenAI 型号误计价。
if normalized := normalizeKnownOpenAICodexModel(modelLower); normalized != "" {
switch normalized {
case "gpt-5.5":
@@ -332,11 +332,14 @@ func TestCalculateCost_LongContextAppliesMultiplierToCacheCreation5mAnd1h(t *tes
func TestGetFallbackPricing_FamilyMatching(t *testing.T) {
svc := newTestBillingService()
// expectedOutput / expectedCacheRead 为 0 时跳过该字段断言(保持与原有用例兼容)。
tests := []struct {
name string
model string
expectedInput float64
expectNilPricing bool
name string
model string
expectedInput float64
expectedOutput float64
expectedCacheRead float64
expectNilPricing bool
}{
{name: "empty model", model: " ", expectNilPricing: true},
{name: "claude opus 4.6", model: "claude-opus-4.6-20260201", expectedInput: 5e-6},
@@ -352,10 +355,34 @@ func TestGetFallbackPricing_FamilyMatching(t *testing.T) {
{name: "openai legacy gpt5.1 codex falls back to gpt5.3 codex", model: "gpt-5.1-codex", expectedInput: 1.5e-6},
{name: "openai legacy codex mini latest falls back to gpt5.3 codex", model: "codex-mini-latest", expectedInput: 1.5e-6},
{name: "openai unknown no fallback", model: "gpt-unknown-model", expectNilPricing: true},
{name: "deepseek v4 pro", model: "deepseek-v4-pro", expectedInput: 4.35e-7},
{name: "deepseek v4 flash", model: "deepseek-v4-flash", expectedInput: 1.4e-7},
{name: "deepseek chat alias → flash", model: "deepseek-chat", expectedInput: 1.4e-7},
{name: "deepseek reasoner alias → flash", model: "deepseek-reasoner", expectedInput: 1.4e-7},
{
name: "deepseek v4 pro",
model: "deepseek-v4-pro",
expectedInput: 4.35e-7,
expectedOutput: 8.7e-7,
expectedCacheRead: 3.625e-9,
},
{
name: "deepseek v4 flash",
model: "deepseek-v4-flash",
expectedInput: 1.4e-7,
expectedOutput: 2.8e-7,
expectedCacheRead: 2.8e-9,
},
{
name: "deepseek chat alias → flash",
model: "deepseek-chat",
expectedInput: 1.4e-7,
expectedOutput: 2.8e-7,
expectedCacheRead: 2.8e-9,
},
{
name: "deepseek reasoner alias → flash",
model: "deepseek-reasoner",
expectedInput: 1.4e-7,
expectedOutput: 2.8e-7,
expectedCacheRead: 2.8e-9,
},
{name: "non supported family", model: "qwen-max", expectNilPricing: true},
}
@@ -368,6 +395,14 @@ func TestGetFallbackPricing_FamilyMatching(t *testing.T) {
}
require.NotNil(t, pricing)
require.InDelta(t, tt.expectedInput, pricing.InputPricePerToken, 1e-12)
if tt.expectedOutput != 0 {
require.InDelta(t, tt.expectedOutput, pricing.OutputPricePerToken, 1e-12,
"OutputPricePerToken mismatch for %s", tt.model)
}
if tt.expectedCacheRead != 0 {
require.InDelta(t, tt.expectedCacheRead, pricing.CacheReadPricePerToken, 1e-14,
"CacheReadPricePerToken mismatch for %s", tt.model)
}
})
}
}