91 lines
3.2 KiB
Go
91 lines
3.2 KiB
Go
package kernel
|
|
|
|
import (
|
|
"errors"
|
|
"math"
|
|
"testing"
|
|
)
|
|
|
|
func TestTokenBillingAmount(t *testing.T) {
|
|
for _, test := range []struct {
|
|
name string
|
|
multiplier int64
|
|
terms []TokenBillingTerm
|
|
want int64
|
|
}{
|
|
{
|
|
name: "maximum configured price", multiplier: 10_000,
|
|
terms: []TokenBillingTerm{{Tokens: 10_000_000, PriceMicrocredits: 1_000_000_000_000}},
|
|
want: 10_000_000_000_000,
|
|
},
|
|
{
|
|
name: "maximum configured price with multiplier", multiplier: 12_500,
|
|
terms: []TokenBillingTerm{{Tokens: 10_000_000, PriceMicrocredits: 1_000_000_000_000}},
|
|
want: 12_500_000_000_000,
|
|
},
|
|
{
|
|
name: "round once after combining terms", multiplier: 10_000,
|
|
terms: []TokenBillingTerm{{Tokens: 1, PriceMicrocredits: 400_000}, {Tokens: 1, PriceMicrocredits: 400_000}, {Tokens: 1, PriceMicrocredits: 100_000}},
|
|
want: 1,
|
|
},
|
|
{
|
|
name: "apply multiplier before rounding", multiplier: 12_500,
|
|
terms: []TokenBillingTerm{{Tokens: 1, PriceMicrocredits: 400_000}, {Tokens: 1, PriceMicrocredits: 400_000}},
|
|
want: 1,
|
|
},
|
|
{
|
|
name: "fractional microcredit rounds up", multiplier: 1,
|
|
terms: []TokenBillingTerm{{Tokens: 1, PriceMicrocredits: 1}},
|
|
want: 1,
|
|
},
|
|
{
|
|
name: "maximum int64 result after overflowing intermediate sum", multiplier: 10_000,
|
|
terms: []TokenBillingTerm{{Tokens: math.MaxInt64, PriceMicrocredits: 500_000}, {Tokens: math.MaxInt64, PriceMicrocredits: 500_000}},
|
|
want: math.MaxInt64,
|
|
},
|
|
{
|
|
name: "free usage", multiplier: math.MaxInt64,
|
|
terms: []TokenBillingTerm{{Tokens: math.MaxInt64, PriceMicrocredits: 0}},
|
|
want: 0,
|
|
},
|
|
} {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
amount, err := TokenBillingAmount(test.multiplier, test.terms...)
|
|
if err != nil || amount != test.want {
|
|
t.Fatalf("TokenBillingAmount() = %d, %v; want %d", amount, err, test.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTokenBillingAmountRejectsInvalidParametersAndFinalOverflow(t *testing.T) {
|
|
for _, test := range []struct {
|
|
name string
|
|
multiplier int64
|
|
terms []TokenBillingTerm
|
|
wantErr error
|
|
}{
|
|
{name: "zero multiplier", terms: []TokenBillingTerm{{Tokens: 1, PriceMicrocredits: 1}}, wantErr: ErrInvalidTokenBilling},
|
|
{name: "negative multiplier", multiplier: -1, wantErr: ErrInvalidTokenBilling},
|
|
{name: "negative tokens", multiplier: 10_000, terms: []TokenBillingTerm{{Tokens: -1}}, wantErr: ErrInvalidTokenBilling},
|
|
{name: "negative price even with zero tokens", multiplier: 10_000, terms: []TokenBillingTerm{{PriceMicrocredits: -1}}, wantErr: ErrInvalidTokenBilling},
|
|
{
|
|
name: "final amount overflow", multiplier: 10_001,
|
|
terms: []TokenBillingTerm{{Tokens: math.MaxInt64, PriceMicrocredits: 1_000_000}},
|
|
wantErr: ErrTokenBillingOverflow,
|
|
},
|
|
{
|
|
name: "rounding causes final overflow", multiplier: 10_000,
|
|
terms: []TokenBillingTerm{{Tokens: math.MaxInt64, PriceMicrocredits: 1_000_000}, {Tokens: 1, PriceMicrocredits: 1}},
|
|
wantErr: ErrTokenBillingOverflow,
|
|
},
|
|
} {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
amount, err := TokenBillingAmount(test.multiplier, test.terms...)
|
|
if amount != 0 || !errors.Is(err, test.wantErr) {
|
|
t.Fatalf("TokenBillingAmount() = %d, %v; want 0, %v", amount, err, test.wantErr)
|
|
}
|
|
})
|
|
}
|
|
}
|