main_test.go 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. package main
  2. import (
  3. "testing"
  4. "time"
  5. "github.com/Wei-Shaw/sub2api/internal/service"
  6. "github.com/stretchr/testify/require"
  7. )
  8. func TestParsePreviewInputsIgnoresNullUserOverride(t *testing.T) {
  9. raw := []byte(`{
  10. "groups": [{
  11. "group": {
  12. "id": 50,
  13. "name": "preview",
  14. "platform": "openai",
  15. "rate_multiplier": 0.5,
  16. "subscription_type": "standard",
  17. "profit_control_enabled": false,
  18. "profit_min_margin": 0.1,
  19. "profit_safety_buffer": 0
  20. },
  21. "accounts": [{
  22. "id": 1,
  23. "name": "cheap",
  24. "platform": "openai",
  25. "type": "apikey",
  26. "rate_multiplier": 0.2
  27. }],
  28. "user_overrides": {"40": null, "41": 0.4},
  29. "models": ["gpt-test"]
  30. }]
  31. }`)
  32. inputs, err := parsePreviewInputs(raw, true)
  33. require.NoError(t, err)
  34. require.Len(t, inputs, 1)
  35. require.Equal(t, map[int64]float64{41: 0.4}, inputs[0].UserOverrides)
  36. require.True(t, inputs[0].AssumeEnabled)
  37. report := service.PreviewProfitAdmission(inputs, time.Date(2026, 1, 15, 8, 30, 0, 0, time.UTC))[0]
  38. require.InDelta(t, 0.4, report.MinEffectiveD, 1e-12, "null 覆盖不能被解码成 0 倍率")
  39. require.InDelta(t, 0.36, report.ThresholdMinD, 1e-12)
  40. }
  41. func TestParsePreviewInputsRejectsEmptyGroups(t *testing.T) {
  42. for _, raw := range [][]byte{
  43. []byte(`{"groups":null}`),
  44. []byte(`{"groups":[]}`),
  45. } {
  46. inputs, err := parsePreviewInputs(raw, false)
  47. require.ErrorContains(t, err, "input contains no groups")
  48. require.Nil(t, inputs)
  49. }
  50. }
  51. // TestModelsWithZeroRemainingWarnings 钉死两档 D 的归零告警分工:
  52. // 默认 D 归零由 modelsWithZeroRemaining 报告;默认 D 仍有账号但最低有效 D
  53. // (分组内存在更低的用户级倍率覆盖)归零的模型必须单独告警——那些用户的该
  54. // 模型会全黑,只看默认 D 完全看不出来。两档都为 0 时不重复告警。
  55. func TestModelsWithZeroRemainingWarnings(t *testing.T) {
  56. report := service.ProfitPreviewGroupReport{
  57. RemainingByModel: map[string]int{
  58. "both-zero": 0,
  59. "min-d-zero": 2,
  60. "healthy": 3,
  61. "min-d-zero-alt": 1,
  62. },
  63. RemainingByModelMinD: map[string]int{
  64. "both-zero": 0,
  65. "min-d-zero": 0,
  66. "healthy": 3,
  67. "min-d-zero-alt": 0,
  68. },
  69. }
  70. if got := modelsWithZeroRemaining(report); len(got) != 1 || got[0] != "both-zero" {
  71. t.Fatalf("默认D归零告警应只覆盖 both-zero,got %v", got)
  72. }
  73. got := modelsWithZeroRemainingUnderMinD(report)
  74. want := []string{"min-d-zero", "min-d-zero-alt"}
  75. if len(got) != len(want) {
  76. t.Fatalf("最低有效D归零告警不符: got %v want %v", got, want)
  77. }
  78. for i := range want {
  79. if got[i] != want[i] {
  80. t.Fatalf("最低有效D归零告警不符(应按模型名排序): got %v want %v", got, want)
  81. }
  82. }
  83. }