92 lines
3.0 KiB
Go
92 lines
3.0 KiB
Go
package pricing_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"billing/internal/pricing"
|
|
)
|
|
|
|
func testPolicy() pricing.Policy {
|
|
return pricing.Policy{
|
|
Model: "gpt-5.6-sol",
|
|
Base: pricing.Rates{
|
|
InputMicrosPer1M: 2_500_000,
|
|
CacheReadMicrosPer1M: 250_000,
|
|
CacheWriteMicrosPer1M: 3_125_000,
|
|
OutputMicrosPer1M: 15_000_000,
|
|
},
|
|
LongContext: &pricing.LongContext{
|
|
ThresholdInputTokens: 272_000,
|
|
Comparison: "gt",
|
|
Rates: pricing.Rates{
|
|
InputMicrosPer1M: 5_000_000,
|
|
CacheReadMicrosPer1M: 500_000,
|
|
CacheWriteMicrosPer1M: 6_250_000,
|
|
OutputMicrosPer1M: 22_500_000,
|
|
},
|
|
},
|
|
FastPricingEnabled: true,
|
|
FastMultiplier: pricing.Ratio{Numerator: 5, Denominator: 2},
|
|
}
|
|
}
|
|
|
|
func TestCalculateUsesEachTokenBucketOnce(t *testing.T) {
|
|
result, err := pricing.Calculate(testPolicy(), pricing.Usage{
|
|
InputTokens: 1_000_000, CacheReadTokens: 400_000, CacheWriteTokens: 100_000, OutputTokens: 500_000,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// The request is above the threshold, so all buckets use long-context rates.
|
|
if result.CostMicros != 14_575_000 || result.PriceTier != "long_context" || result.FastApplied {
|
|
t.Fatalf("unexpected result: %+v", result)
|
|
}
|
|
}
|
|
|
|
func TestCalculateCanDisableFastPricingWithoutChangingRequestMode(t *testing.T) {
|
|
policy := testPolicy()
|
|
policy.FastPricingEnabled = false
|
|
result, err := pricing.Calculate(policy, pricing.Usage{InputTokens: 100_000, OutputTokens: 10_000, ServiceTier: "priority"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if result.CostMicros != 400_000 || !result.FastRequested || result.FastApplied || result.MultiplierNumerator != 1 || result.MultiplierDenominator != 1 {
|
|
t.Fatalf("unexpected disabled Fast pricing result: %+v", result)
|
|
}
|
|
}
|
|
|
|
func TestCalculateRecognizesPassedFastSpeed(t *testing.T) {
|
|
result, err := pricing.Calculate(testPolicy(), pricing.Usage{InputTokens: 100_000, Speed: "fast"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !result.FastRequested || !result.FastApplied || result.CostMicros != 625_000 {
|
|
t.Fatalf("unexpected speed=fast result: %+v", result)
|
|
}
|
|
}
|
|
|
|
func TestCalculateUsesStrictThresholdAndAppliesFastOnce(t *testing.T) {
|
|
policy := testPolicy()
|
|
base, err := pricing.Calculate(policy, pricing.Usage{InputTokens: 272_000, OutputTokens: 10_000, ServiceTier: "priority"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if base.PriceTier != "base" || base.CostMicros != 2_075_000 || !base.FastApplied || base.MultiplierNumerator != 5 || base.MultiplierDenominator != 2 {
|
|
t.Fatalf("unexpected threshold result: %+v", base)
|
|
}
|
|
long, err := pricing.Calculate(policy, pricing.Usage{InputTokens: 272_001, OutputTokens: 10_000, ServiceTier: "priority"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if long.PriceTier != "long_context" || long.CostMicros != 3_962_513 {
|
|
t.Fatalf("unexpected long-context result: %+v", long)
|
|
}
|
|
}
|
|
|
|
func TestCalculateRejectsOverlappingCacheCounts(t *testing.T) {
|
|
_, err := pricing.Calculate(testPolicy(), pricing.Usage{InputTokens: 10, CacheReadTokens: 8, CacheWriteTokens: 3})
|
|
if err == nil {
|
|
t.Fatal("overlapping cache counts unexpectedly accepted")
|
|
}
|
|
}
|