107 lines
5.2 KiB
Go
107 lines
5.2 KiB
Go
package billing
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"os"
|
|
"testing"
|
|
)
|
|
|
|
func TestBillingCoreFixtureIsConsumedByGo(t *testing.T) {
|
|
data, err := os.ReadFile("../../../contracts/billing/core-v1.json")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var fixture struct {
|
|
Currency string `json:"currency"`
|
|
MoneyUnit string `json:"moneyUnit"`
|
|
Statuses struct {
|
|
InsufficientBalance int `json:"insufficientBalance"`
|
|
IdempotencyConflict int `json:"idempotencyConflict"`
|
|
} `json:"statuses"`
|
|
IdempotencyKeys struct {
|
|
Charge string `json:"charge"`
|
|
Refund string `json:"refund"`
|
|
} `json:"idempotencyKeys"`
|
|
}
|
|
if err := json.Unmarshal(data, &fixture); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if fixture.Currency != CurrencyCNY || fixture.MoneyUnit != "fen" || fixture.Statuses.InsufficientBalance != 402 || fixture.Statuses.IdempotencyConflict != 409 || fixture.IdempotencyKeys.Charge != "job-charge:{jobId}" || fixture.IdempotencyKeys.Refund != "job-refund:{jobId}" {
|
|
t.Fatalf("fixture = %#v", fixture)
|
|
}
|
|
}
|
|
|
|
func TestCatalogQuotesMostSpecificRuleWithCeiledQuantityAndTierFactors(t *testing.T) {
|
|
catalog := Catalog{Rules: []PriceRule{
|
|
{ID: "generic", Provider: "evolink", Capability: "image.generate", Unit: UnitImage, StandardUnitPriceFen: 10, MarkupMultiplier: 1.2, Enabled: true},
|
|
{ID: "specific", Provider: "evolink", Capability: "image.generate", ReqKey: "gpt-image-2", Unit: UnitImage, QuantitySource: QuantityImageCount, StandardUnitPriceFen: 34, MarkupMultiplier: 1.2, Enabled: true, Conditions: Conditions{"quality": "high"}, Dimensions: []ParameterDimension{
|
|
{Key: "quality", Tiers: []ParameterTier{{Value: "high", StandardFactor: 4, MarkupMultiplier: 1.5, Enabled: true}}},
|
|
{Key: "resolution", DefaultValue: "1K", Tiers: []ParameterTier{{Value: "1K", StandardFactor: 2, MarkupMultiplier: 1.8, Enabled: true}}},
|
|
}},
|
|
}}
|
|
quote, err := catalog.Quote(QuoteInput{Provider: "evolink", Capability: "image.generate", ReqKey: "gpt-image-2", Parameters: Parameters{"quality": "HIGH", "imageCount": 1.2}})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if quote.PriceRuleID != "specific" || quote.Quantity != 2 || quote.StandardUnitPriceFen != 272 || quote.MarkupMultiplier != 1.8 || quote.AmountFen != 980 || quote.Currency != CurrencyCNY {
|
|
t.Fatalf("quote = %#v", quote)
|
|
}
|
|
}
|
|
|
|
func TestCatalogRejectsAmbiguousWinners(t *testing.T) {
|
|
rules := []PriceRule{
|
|
{ID: "a", Provider: "bailian", Capability: "image.generate", Unit: UnitRequest, StandardUnitPriceFen: 1, MarkupMultiplier: 1, Enabled: true},
|
|
{ID: "b", Provider: "bailian", Capability: "image.generate", Unit: UnitRequest, StandardUnitPriceFen: 2, MarkupMultiplier: 1, Enabled: true},
|
|
}
|
|
_, err := (Catalog{Rules: rules}).Quote(QuoteInput{Provider: "bailian", Capability: "image.generate"})
|
|
if !errors.Is(err, ErrAmbiguousPriceRule) {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCatalogExemptsDisabledMockAndSuperAdmin(t *testing.T) {
|
|
rule := PriceRule{ID: "r", Provider: "bailian", Capability: "image.generate", Unit: UnitRequest, StandardUnitPriceFen: 10, MarkupMultiplier: 1, Enabled: true}
|
|
for _, input := range []QuoteInput{
|
|
{BillingDisabled: true, Provider: "bailian", Capability: "image.generate"},
|
|
{Provider: "mock", Capability: "image.generate"},
|
|
} {
|
|
quote, err := (Catalog{Rules: []PriceRule{rule}}).Quote(input)
|
|
if err != nil || quote != nil {
|
|
t.Fatalf("Quote(%#v) = %#v, %v", input, quote, err)
|
|
}
|
|
}
|
|
quote, err := (Catalog{Rules: []PriceRule{rule}}).Quote(QuoteInput{Provider: "bailian", Capability: "image.generate", Source: "platform", Role: "super_admin"})
|
|
if err != nil || quote == nil || !quote.QuotaExempt {
|
|
t.Fatalf("quote = %#v, %v", quote, err)
|
|
}
|
|
}
|
|
|
|
func TestCatalogMatchesLegacyVariantKeyAsEffectiveConditions(t *testing.T) {
|
|
rules := []PriceRule{
|
|
{ID: "720", Provider: "seedance", Capability: "video.generate", ReqKey: "seedance-2", VariantKey: "resolution=720p", Unit: UnitVideoSecond, StandardUnitPriceFen: 99, MarkupMultiplier: 1.2, Enabled: true},
|
|
{ID: "1080", Provider: "seedance", Capability: "video.generate", ReqKey: "seedance-2", VariantKey: "resolution=1080p", Unit: UnitVideoSecond, StandardUnitPriceFen: 248, MarkupMultiplier: 1.2, Enabled: true},
|
|
}
|
|
quote, err := (Catalog{Rules: rules}).Quote(QuoteInput{
|
|
Provider: "seedance", Capability: "video.generate", ReqKey: "seedance-2",
|
|
Parameters: Parameters{"resolution": " 720P ", "duration": 5.0},
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if quote.PriceRuleID != "720" || quote.VariantKey != "resolution=720p" || quote.AmountFen != 594 {
|
|
t.Fatalf("quote = %#v", quote)
|
|
}
|
|
if quote.Conditions["resolution"] != "720p" {
|
|
t.Fatalf("effective conditions = %#v", quote.Conditions)
|
|
}
|
|
}
|
|
|
|
func TestCatalogExplicitConditionsOverrideLegacyVariantKey(t *testing.T) {
|
|
rule := PriceRule{ID: "override", Provider: "seedance", Capability: "video.generate", VariantKey: "resolution=720p", Conditions: Conditions{"resolution": "1080p"}, Unit: UnitRequest, StandardUnitPriceFen: 1, MarkupMultiplier: 1, Enabled: true}
|
|
quote, err := (Catalog{Rules: []PriceRule{rule}}).Quote(QuoteInput{Provider: "seedance", Capability: "video.generate", Parameters: Parameters{"resolution": "1080P"}})
|
|
if err != nil || quote == nil || quote.Conditions["resolution"] != "1080p" {
|
|
t.Fatalf("quote = %#v, err = %v", quote, err)
|
|
}
|
|
}
|