Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 

148 строки
5.9 KiB

  1. package helper
  2. import (
  3. "testing"
  4. "github.com/QuantumNous/new-api/common"
  5. "github.com/QuantumNous/new-api/types"
  6. "github.com/stretchr/testify/require"
  7. )
  8. func TestPricingLookup_MatchSpecificity(t *testing.T) {
  9. cfg := testPricingLookupConfig(types.PricingFallbackReject)
  10. resolved := &ResolvedDimensionValues{Values: map[string]any{"resolution": "720P", "duration": 10.0}}
  11. result, taskErr := lookupPricingConfig(cfg, resolved)
  12. require.Nil(t, taskErr)
  13. require.Equal(t, types.PricingModeMatched, result.Mode)
  14. require.Equal(t, 0.08, result.PriceUSD)
  15. require.Equal(t, "720P", result.Snapshot["resolution"])
  16. require.Equal(t, 10.0, result.Snapshot["duration"])
  17. }
  18. func TestPricingLookup_StringDimensionMatchesCaseInsensitive(t *testing.T) {
  19. cfg := testPricingLookupConfig(types.PricingFallbackReject)
  20. resolved := &ResolvedDimensionValues{Values: map[string]any{"resolution": "720p", "duration": 10.0}}
  21. result, taskErr := lookupPricingConfig(cfg, resolved)
  22. require.Nil(t, taskErr)
  23. require.Equal(t, types.PricingModeMatched, result.Mode)
  24. require.Equal(t, 0.08, result.PriceUSD)
  25. require.Equal(t, "720p", result.Snapshot["resolution"])
  26. }
  27. func TestPricingLookup_WildcardFallbackMatch(t *testing.T) {
  28. cfg := testPricingLookupConfig(types.PricingFallbackReject)
  29. resolved := &ResolvedDimensionValues{Values: map[string]any{"resolution": "480P", "duration": 10.0}}
  30. result, taskErr := lookupPricingConfig(cfg, resolved)
  31. require.Nil(t, taskErr)
  32. require.Equal(t, 0.05, result.PriceUSD)
  33. }
  34. func TestPricingLookup_RejectFallback(t *testing.T) {
  35. cfg := testPricingLookupConfig(types.PricingFallbackReject)
  36. resolved := &ResolvedDimensionValues{Values: map[string]any{"resolution": "1080P", "duration": 15.0}}
  37. result, taskErr := lookupPricingConfig(cfg, resolved)
  38. require.Nil(t, result)
  39. require.NotNil(t, taskErr)
  40. require.Equal(t, "pricing_no_match", taskErr.Code)
  41. }
  42. func TestPricingLookup_MaxFallback(t *testing.T) {
  43. cfg := testPricingLookupConfig(types.PricingFallbackMax)
  44. resolved := &ResolvedDimensionValues{Values: map[string]any{"resolution": "1080P", "duration": 15.0}}
  45. result, taskErr := lookupPricingConfig(cfg, resolved)
  46. require.Nil(t, taskErr)
  47. require.Equal(t, types.PricingModeFallbackMax, result.Mode)
  48. require.Equal(t, 0.1, result.PriceUSD)
  49. require.Equal(t, types.PricingFallbackMax, result.Snapshot["fallback_strategy"])
  50. }
  51. func TestPricingLookup_DefaultFallback(t *testing.T) {
  52. cfg := testPricingLookupConfig(types.PricingFallbackDefault)
  53. cfg.Fallback.DefaultPrice = 0.2
  54. resolved := &ResolvedDimensionValues{Values: map[string]any{"resolution": "1080P", "duration": 15.0}}
  55. result, taskErr := lookupPricingConfig(cfg, resolved)
  56. require.Nil(t, taskErr)
  57. require.Equal(t, types.PricingModeFallbackDefault, result.Mode)
  58. require.Equal(t, 0.2, result.PriceUSD)
  59. }
  60. func TestPricingLookup_MissingDimensionSnapshotMarshalsNull(t *testing.T) {
  61. cfg := testPricingLookupConfig(types.PricingFallbackDefault)
  62. cfg.Fallback.DefaultPrice = 0.2
  63. resolved := &ResolvedDimensionValues{
  64. Values: map[string]any{"resolution": "1080P", "duration": nil},
  65. Missing: map[string]bool{"duration": true},
  66. }
  67. result, taskErr := lookupPricingConfig(cfg, resolved)
  68. require.Nil(t, taskErr)
  69. body, err := common.Marshal(result.Snapshot)
  70. require.NoError(t, err)
  71. require.Contains(t, string(body), `"duration":null`)
  72. }
  73. func TestPricingLookup_DecisionQuota(t *testing.T) {
  74. cfg := testPricingLookupConfig(types.PricingFallbackReject)
  75. result := &pricingLookupResult{Mode: types.PricingModeMatched, PriceUSD: 0.1, Snapshot: map[string]any{"price": 0.1}}
  76. decision := buildMatchedDecision(cfg, result, types.GroupRatioInfo{GroupRatio: 0.5})
  77. require.Equal(t, types.BillingModeMatrix, decision.BillingMode)
  78. require.Equal(t, types.BillingUnitPerCall, decision.BillingUnit)
  79. require.Equal(t, int(0.1*common.QuotaPerUnit*0.5), decision.Quota)
  80. require.True(t, decision.PerCallBilling)
  81. }
  82. func TestPricingLookup_UsageDecisionMinimumPreconsume(t *testing.T) {
  83. cfg := testPricingLookupConfig(types.PricingFallbackReject)
  84. cfg.BillingUnit = types.BillingUnitPer1MTokens
  85. cfg.PreconsumeStrategy = types.PreconsumeStrategyMinimum
  86. result := &pricingLookupResult{Mode: types.PricingModeMatched, PriceUSD: 2.0, Snapshot: map[string]any{"price": 2.0}}
  87. decision := buildMatchedDecision(cfg, result, types.GroupRatioInfo{GroupRatio: 1})
  88. require.Equal(t, 2.0, decision.PriceUSD)
  89. require.Equal(t, 2.0, decision.TokenUnitPriceUSD)
  90. require.Equal(t, minimumUsagePreconsumeQuota(2.0, 1), decision.Quota)
  91. require.False(t, decision.PerCallBilling)
  92. }
  93. func TestPricingLookup_RemixUsageDecisionKeepsDisplayPrice(t *testing.T) {
  94. decision, taskErr := buildRemixMatrixDecision(&types.OriginPricingSnapshot{
  95. PriceUSD: 0,
  96. TokenUnitPriceUSD: 46,
  97. BillingUnit: types.BillingUnitPer1MTokens,
  98. Snapshot: map[string]any{"price": 46},
  99. PerCallBilling: false,
  100. }, types.GroupRatioInfo{GroupRatio: 1})
  101. require.Nil(t, taskErr)
  102. require.Equal(t, 46.0, decision.PriceUSD)
  103. require.Equal(t, 46.0, decision.TokenUnitPriceUSD)
  104. require.Equal(t, minimumUsagePreconsumeQuota(46, 1), decision.Quota)
  105. require.False(t, decision.PerCallBilling)
  106. }
  107. func testPricingLookupConfig(fallback string) *types.PricingConfig {
  108. return &types.PricingConfig{
  109. SchemaVersion: types.PricingSchemaVersion,
  110. Scope: types.PricingScopeModel,
  111. BillingUnit: types.BillingUnitPerCall,
  112. PreconsumeStrategy: types.PreconsumeStrategyExact,
  113. Dimensions: []types.PricingDimension{
  114. {Key: "resolution", Source: "request.resolution", Type: "string"},
  115. {Key: "duration", Source: "request.duration", Type: "number"},
  116. },
  117. Table: []types.PricingRow{
  118. {"resolution": "720P", "duration": 10.0, "price": 0.08, "source": types.PricingRowSourceManual},
  119. {"resolution": "720P", "duration": "*", "price": 0.1, "source": types.PricingRowSourceManual},
  120. {"resolution": "*", "duration": 10.0, "price": 0.05, "source": types.PricingRowSourceManual},
  121. },
  122. Fallback: types.PricingFallback{Strategy: fallback},
  123. }
  124. }