You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

120 rivejä
4.8 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_WildcardFallbackMatch(t *testing.T) {
  19. cfg := testPricingLookupConfig(types.PricingFallbackReject)
  20. resolved := &ResolvedDimensionValues{Values: map[string]any{"resolution": "480P", "duration": 10.0}}
  21. result, taskErr := lookupPricingConfig(cfg, resolved)
  22. require.Nil(t, taskErr)
  23. require.Equal(t, 0.05, result.PriceUSD)
  24. }
  25. func TestPricingLookup_RejectFallback(t *testing.T) {
  26. cfg := testPricingLookupConfig(types.PricingFallbackReject)
  27. resolved := &ResolvedDimensionValues{Values: map[string]any{"resolution": "1080P", "duration": 15.0}}
  28. result, taskErr := lookupPricingConfig(cfg, resolved)
  29. require.Nil(t, result)
  30. require.NotNil(t, taskErr)
  31. require.Equal(t, "pricing_no_match", taskErr.Code)
  32. }
  33. func TestPricingLookup_MaxFallback(t *testing.T) {
  34. cfg := testPricingLookupConfig(types.PricingFallbackMax)
  35. resolved := &ResolvedDimensionValues{Values: map[string]any{"resolution": "1080P", "duration": 15.0}}
  36. result, taskErr := lookupPricingConfig(cfg, resolved)
  37. require.Nil(t, taskErr)
  38. require.Equal(t, types.PricingModeFallbackMax, result.Mode)
  39. require.Equal(t, 0.1, result.PriceUSD)
  40. require.Equal(t, types.PricingFallbackMax, result.Snapshot["fallback_strategy"])
  41. }
  42. func TestPricingLookup_DefaultFallback(t *testing.T) {
  43. cfg := testPricingLookupConfig(types.PricingFallbackDefault)
  44. cfg.Fallback.DefaultPrice = 0.2
  45. resolved := &ResolvedDimensionValues{Values: map[string]any{"resolution": "1080P", "duration": 15.0}}
  46. result, taskErr := lookupPricingConfig(cfg, resolved)
  47. require.Nil(t, taskErr)
  48. require.Equal(t, types.PricingModeFallbackDefault, result.Mode)
  49. require.Equal(t, 0.2, result.PriceUSD)
  50. }
  51. func TestPricingLookup_MissingDimensionSnapshotMarshalsNull(t *testing.T) {
  52. cfg := testPricingLookupConfig(types.PricingFallbackDefault)
  53. cfg.Fallback.DefaultPrice = 0.2
  54. resolved := &ResolvedDimensionValues{
  55. Values: map[string]any{"resolution": "1080P", "duration": nil},
  56. Missing: map[string]bool{"duration": true},
  57. }
  58. result, taskErr := lookupPricingConfig(cfg, resolved)
  59. require.Nil(t, taskErr)
  60. body, err := common.Marshal(result.Snapshot)
  61. require.NoError(t, err)
  62. require.Contains(t, string(body), `"duration":null`)
  63. }
  64. func TestPricingLookup_DecisionQuota(t *testing.T) {
  65. cfg := testPricingLookupConfig(types.PricingFallbackReject)
  66. result := &pricingLookupResult{Mode: types.PricingModeMatched, PriceUSD: 0.1, Snapshot: map[string]any{"price": 0.1}}
  67. decision := buildMatchedDecision(cfg, result, types.GroupRatioInfo{GroupRatio: 0.5})
  68. require.Equal(t, types.BillingModeMatrix, decision.BillingMode)
  69. require.Equal(t, types.BillingUnitPerCall, decision.BillingUnit)
  70. require.Equal(t, int(0.1*common.QuotaPerUnit*0.5), decision.Quota)
  71. require.True(t, decision.PerCallBilling)
  72. }
  73. func TestPricingLookup_UsageDecisionMinimumPreconsume(t *testing.T) {
  74. cfg := testPricingLookupConfig(types.PricingFallbackReject)
  75. cfg.BillingUnit = types.BillingUnitPer1MTokens
  76. cfg.PreconsumeStrategy = types.PreconsumeStrategyMinimum
  77. result := &pricingLookupResult{Mode: types.PricingModeMatched, PriceUSD: 2.0, Snapshot: map[string]any{"price": 2.0}}
  78. decision := buildMatchedDecision(cfg, result, types.GroupRatioInfo{GroupRatio: 1})
  79. require.Equal(t, 2.0, decision.TokenUnitPriceUSD)
  80. require.Equal(t, minimumUsagePreconsumeQuota(2.0, 1), decision.Quota)
  81. require.False(t, decision.PerCallBilling)
  82. }
  83. func testPricingLookupConfig(fallback string) *types.PricingConfig {
  84. return &types.PricingConfig{
  85. SchemaVersion: types.PricingSchemaVersion,
  86. Scope: types.PricingScopeModel,
  87. BillingUnit: types.BillingUnitPerCall,
  88. PreconsumeStrategy: types.PreconsumeStrategyExact,
  89. Dimensions: []types.PricingDimension{
  90. {Key: "resolution", Source: "request.resolution", Type: "string"},
  91. {Key: "duration", Source: "request.duration", Type: "number"},
  92. },
  93. Table: []types.PricingRow{
  94. {"resolution": "720P", "duration": 10.0, "price": 0.08, "source": types.PricingRowSourceManual},
  95. {"resolution": "720P", "duration": "*", "price": 0.1, "source": types.PricingRowSourceManual},
  96. {"resolution": "*", "duration": 10.0, "price": 0.05, "source": types.PricingRowSourceManual},
  97. },
  98. Fallback: types.PricingFallback{Strategy: fallback},
  99. }
  100. }