Files
OSGAccountServer/src/test/kotlin/com/osglab/account/features/credits/CreditServiceTest.kt
T
Rocky d0abe27623
CI / verify (push) Has been cancelled
CI / publish (push) Has been cancelled
Add managed content and keyboard usage insights
Introduce versioned official content workflows and privacy-safe keyboard analytics, while preventing repeat DeviceCheck sign-ins from incorrectly restricting eligible accounts.
2026-08-21 13:34:03 +08:00

810 lines
29 KiB
Kotlin

package com.osglab.account.features.credits
import com.osglab.account.features.credits.domain.CreditCostCalculator
import com.osglab.account.features.credits.domain.CreditConflict
import com.osglab.account.features.credits.domain.CreditRateVersion
import com.osglab.account.features.credits.domain.InsufficientCredits
import com.osglab.account.features.credits.domain.InvalidCreditRequest
import com.osglab.account.features.credits.domain.LedgerEntryType
import com.osglab.account.features.credits.domain.ReservationStatus
import com.osglab.account.features.credits.domain.ReservationStateRules
import com.osglab.account.features.credits.domain.UsageKind
import com.osglab.account.features.credits.domain.UsageMeasurement
import com.osglab.account.features.credits.domain.externalIdempotencyKey
import com.osglab.account.features.credits.services.CreditService
import com.osglab.account.features.credits.services.ReferralRewardConfig
import com.osglab.account.features.credits.services.signupTrialIdempotencyKey
import com.osglab.account.features.referrals.domain.ReferralBinding
import com.osglab.account.features.referrals.domain.ReferralCampaign
import com.osglab.account.features.referrals.domain.ReferralCampaignBudget
import com.osglab.account.features.referrals.domain.ReferralRewardStatus
import io.kotest.core.spec.style.FunSpec
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.matchers.collections.shouldHaveSize
import io.kotest.matchers.longs.shouldBeExactly
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import io.kotest.matchers.types.shouldBeInstanceOf
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import java.time.Clock
import java.time.Instant
import java.time.ZoneOffset
import java.util.UUID
import kotlin.random.Random
class CreditServiceTest : FunSpec({
val now = Instant.parse("2026-08-15T00:00:00Z")
test("ASR and LLM rates round each billed dimension upward") {
CreditCostCalculator.calculate(
asrRate(now),
UsageMeasurement.Asr(durationMillis = 101),
) shouldBeExactly 2
CreditCostCalculator.calculate(
llmRate(now),
UsageMeasurement.Llm(inputTokens = 1001, outputTokens = 1),
) shouldBeExactly 4
}
test("smaller production unit bills each started interval") {
val productionAsr = asrRate(now).copy(asrMillisDenominator = 3_000)
CreditCostCalculator.calculate(
productionAsr,
UsageMeasurement.Asr(durationMillis = 1),
) shouldBeExactly 1
CreditCostCalculator.calculate(
productionAsr,
UsageMeasurement.Asr(durationMillis = 3_000),
) shouldBeExactly 1
CreditCostCalculator.calculate(
productionAsr,
UsageMeasurement.Asr(durationMillis = 3_001),
) shouldBeExactly 2
val productionLlm = llmRate(now).copy(
inputCreditsNumerator = 1,
inputTokensDenominator = 1_000,
outputCreditsNumerator = 1,
outputTokensDenominator = 400,
)
CreditCostCalculator.calculate(
productionLlm,
UsageMeasurement.Llm(inputTokens = 1_001, outputTokens = 401),
) shouldBeExactly 4
}
test("cost calculation avoids intermediate overflow and rejects an unrepresentable result") {
CreditCostCalculator.calculate(
asrRate(now).copy(
asrCreditsNumerator = 2,
asrMillisDenominator = 2,
),
UsageMeasurement.Asr(Long.MAX_VALUE),
) shouldBeExactly Long.MAX_VALUE
shouldThrow<InvalidCreditRequest> {
CreditCostCalculator.calculate(
asrRate(now).copy(
asrCreditsNumerator = 2,
asrMillisDenominator = 1,
),
UsageMeasurement.Asr(Long.MAX_VALUE),
)
}
}
test("signup grant is idempotent") {
val store = storeWithRates(now)
val service = service(store, now)
val userId = UUID.randomUUID()
service.grantSignupTrial(userId, 100, "signup-key-001")
service.grantSignupTrial(userId, 100, "signup-key-001")
store.balance(userId) shouldBeExactly 100
store.ledger.filter { it.type == LedgerEntryType.SIGNUP_TRIAL } shouldHaveSize 1
}
test("signup trial ledger is the authoritative account-level claim record") {
val store = storeWithRates(now)
val service = service(store, now)
val userId = UUID.randomUUID()
service.hasSignupTrial(userId) shouldBe false
service.grantSignupTrial(userId, 100, signupTrialIdempotencyKey(userId))
service.hasSignupTrial(userId) shouldBe true
}
test("manual grant appends one linked audit and ledger entry") {
val store = storeWithRates(now)
val service = service(store, now)
val userId = UUID.randomUUID()
store.registeredUsers += userId
val result = service.grantManual(
operatorId = TEST_OPERATOR_ID,
userId = userId,
credits = 250,
reason = "Customer support adjustment",
requestId = "support-ticket-1042",
idempotencyKey = "manual-grant-key-001",
)
result.replayed shouldBe false
result.balanceAfter shouldBeExactly 250
store.balance(userId) shouldBeExactly 250
store.manualGrants.single() shouldBe result.grant
store.adminAudits.single().id shouldBe result.grant.auditLogId
store.ledger.single { it.type == LedgerEntryType.MANUAL_GRANT }.let { ledger ->
ledger.referenceId shouldBe result.grant.id
ledger.id shouldBe result.grant.ledgerEntryId
}
}
test("manual grant replay is stable and rejects changed parameters") {
val store = storeWithRates(now)
val service = service(store, now)
val userId = UUID.randomUUID()
store.registeredUsers += userId
val first = service.grantManual(
TEST_OPERATOR_ID,
userId,
100,
"Retention credit",
"support-ticket-1043",
"manual-grant-key-002",
)
val replay = service.grantManual(
TEST_OPERATOR_ID,
userId,
100,
"Retention credit",
"support-ticket-1043",
"manual-grant-key-002",
)
replay.grant shouldBe first.grant
replay.replayed shouldBe true
shouldThrow<CreditConflict> {
service.grantManual(
TEST_OPERATOR_ID,
userId,
101,
"Retention credit",
"support-ticket-1043",
"manual-grant-key-002",
)
}
store.balance(userId) shouldBeExactly 100
store.manualGrants shouldHaveSize 1
store.ledger.filter { it.type == LedgerEntryType.MANUAL_GRANT } shouldHaveSize 1
}
test("manual grant validates positive amount and rolls back an audit failure") {
val store = storeWithRates(now)
val service = service(store, now)
val userId = UUID.randomUUID()
store.registeredUsers += userId
shouldThrow<InvalidCreditRequest> {
service.grantManual(
TEST_OPERATOR_ID,
userId,
0,
"Invalid adjustment",
"support-ticket-1044",
"manual-grant-key-003",
)
}
store.failNextManualGrantInsert = true
shouldThrow<IllegalStateException> {
service.grantManual(
TEST_OPERATOR_ID,
userId,
50,
"Rollback adjustment",
"support-ticket-1045",
"manual-grant-key-004",
)
}
store.balance(userId) shouldBeExactly 0
store.manualGrants shouldHaveSize 0
store.adminAudits shouldHaveSize 0
store.ledger.filter { it.type == LedgerEntryType.MANUAL_GRANT } shouldHaveSize 0
}
test("concurrent manual grant replay credits exactly once") {
val store = storeWithRates(now)
val service = service(store, now)
val userId = UUID.randomUUID()
store.registeredUsers += userId
val results = coroutineScope {
List(8) {
async(Dispatchers.Default) {
service.grantManual(
TEST_OPERATOR_ID,
userId,
75,
"Concurrent adjustment",
"support-ticket-1046",
"manual-grant-key-005",
)
}
}.awaitAll()
}
results.map { it.grant.id }.distinct() shouldHaveSize 1
store.balance(userId) shouldBeExactly 75
store.manualGrants shouldHaveSize 1
store.ledger.filter { it.type == LedgerEntryType.MANUAL_GRANT } shouldHaveSize 1
}
test("manual grant supports the maximum balance and rejects overflow") {
val store = storeWithRates(now)
val service = service(store, now)
val userId = UUID.randomUUID()
store.registeredUsers += userId
service.grantManual(
TEST_OPERATOR_ID,
userId,
Long.MAX_VALUE,
"Maximum supported adjustment",
"support-ticket-1047",
"manual-grant-key-006",
)
shouldThrow<InvalidCreditRequest> {
service.grantManual(
TEST_OPERATOR_ID,
userId,
1,
"Overflow adjustment",
"support-ticket-1048",
"manual-grant-key-007",
)
}
store.balance(userId) shouldBeExactly Long.MAX_VALUE
store.manualGrants shouldHaveSize 1
}
test("balance overflow rolls back without appending a ledger entry") {
val store = storeWithRates(now)
val service = service(store, now)
val userId = UUID.randomUUID()
service.grantSignupTrial(userId, Long.MAX_VALUE, "signup-max-key")
shouldThrow<InvalidCreditRequest> {
service.grantSignupTrial(userId, 1, "signup-overflow-key")
}
store.balance(userId) shouldBeExactly Long.MAX_VALUE
store.ledger.filter { it.userId == userId } shouldHaveSize 1
}
test("concurrent reservations cannot make the account negative") {
val store = storeWithRates(now)
val service = service(store, now)
val userId = UUID.randomUUID()
service.grantSignupTrial(userId, 100, "signup-key-002")
val results = coroutineScope {
listOf("reserve-key-001", "reserve-key-002").map { key ->
async(Dispatchers.Default) {
runCatching {
service.reserve(
userId = userId,
provider = "asr-provider",
model = "asr-model",
estimatedUsage = UsageMeasurement.Asr(6_000),
managedCall = true,
idempotencyKey = key,
)
}
}
}.awaitAll()
}
results.count(Result<*>::isSuccess) shouldBe 1
results.single(Result<*>::isFailure).exceptionOrNull()
.shouldBeInstanceOf<InsufficientCredits>()
store.balance(userId) shouldBeExactly 40
}
test("first positive managed settlement rewards both users exactly once") {
val store = storeWithRates(now)
val service = service(store, now)
val inviter = UUID.randomUUID()
val invitee = UUID.randomUUID()
val binding = ReferralBinding(
id = UUID.randomUUID(),
inviterUserId = inviter,
inviteeUserId = invitee,
codeId = UUID.randomUUID(),
boundAt = now,
rewardedAt = null,
rewardSettlementId = null,
)
store.inTransaction { it.referrals.insertBindingIfAbsent(binding) }
service.grantSignupTrial(invitee, 100, "signup-key-003")
val reservation = service.reserve(
userId = invitee,
provider = "asr-provider",
model = "asr-model",
estimatedUsage = UsageMeasurement.Asr(1_000),
managedCall = true,
idempotencyKey = "reserve-key-003",
)
val first = service.settle(
invitee,
reservation.id,
UsageMeasurement.Asr(500),
"settle-key-003",
)
val retried = service.settle(
invitee,
reservation.id,
UsageMeasurement.Asr(500),
"settle-key-003",
)
first.status shouldBe ReservationStatus.SETTLED
retried shouldBe first
store.balance(invitee) shouldBeExactly 125
store.balance(inviter) shouldBeExactly 30
store.ledger.filter {
it.type == LedgerEntryType.REFERRAL_INVITEE ||
it.type == LedgerEntryType.REFERRAL_INVITER
} shouldHaveSize 2
store.usageRecords shouldHaveSize 1
store.usageRecords.single().rateVersionId shouldBe reservation.rateVersionId
store.bindings.getValue(invitee).rewardSettlementId shouldBe reservation.id
}
test("zero-cost managed settlement does not consume first valid referral reward") {
val store = storeWithRates(now)
val service = service(store, now)
val inviter = UUID.randomUUID()
val invitee = UUID.randomUUID()
store.inTransaction {
it.referrals.insertBindingIfAbsent(
ReferralBinding(
id = UUID.randomUUID(),
inviterUserId = inviter,
inviteeUserId = invitee,
codeId = UUID.randomUUID(),
boundAt = now,
rewardedAt = null,
rewardSettlementId = null,
),
)
}
service.grantSignupTrial(invitee, 100, "zero-signup-key")
val zeroCost = service.reserve(
invitee,
"asr-provider",
"asr-model",
UsageMeasurement.Asr(1_000),
managedCall = true,
idempotencyKey = "zero-reserve-key",
)
service.settle(
invitee,
zeroCost.id,
UsageMeasurement.Asr(0),
"zero-settle-key",
)
store.bindings.getValue(invitee).rewardStatus shouldBe ReferralRewardStatus.PENDING
val qualifying = service.reserve(
invitee,
"asr-provider",
"asr-model",
UsageMeasurement.Asr(1_000),
managedCall = true,
idempotencyKey = "valid-reserve-key",
)
service.settle(
invitee,
qualifying.id,
UsageMeasurement.Asr(1),
"valid-settle-key",
)
store.bindings.getValue(invitee).rewardSettlementId shouldBe qualifying.id
store.ledger.count {
it.type == LedgerEntryType.REFERRAL_INVITER ||
it.type == LedgerEntryType.REFERRAL_INVITEE
} shouldBe 2
}
test("concurrent settlement replay grants both referral sides only once") {
val store = storeWithRates(now)
val service = service(store, now)
val inviter = UUID.randomUUID()
val invitee = UUID.randomUUID()
store.inTransaction {
it.referrals.insertBindingIfAbsent(
ReferralBinding(
id = UUID.randomUUID(),
inviterUserId = inviter,
inviteeUserId = invitee,
codeId = UUID.randomUUID(),
boundAt = now,
rewardedAt = null,
rewardSettlementId = null,
),
)
}
service.grantSignupTrial(invitee, 100, "concurrent-signup-key")
val reservation = service.reserve(
userId = invitee,
provider = "asr-provider",
model = "asr-model",
estimatedUsage = UsageMeasurement.Asr(1_000),
managedCall = true,
idempotencyKey = "concurrent-reserve-key",
)
val results = coroutineScope {
List(8) {
async(Dispatchers.Default) {
service.settle(
userId = invitee,
reservationId = reservation.id,
actualUsage = UsageMeasurement.Asr(500),
idempotencyKey = "concurrent-settle-key",
)
}
}.awaitAll()
}
results.distinct() shouldHaveSize 1
store.usageRecords shouldHaveSize 1
store.ledger.count {
it.type == LedgerEntryType.REFERRAL_INVITEE ||
it.type == LedgerEntryType.REFERRAL_INVITER
} shouldBe 2
store.balance(inviter) shouldBeExactly 30
store.balance(invitee) shouldBeExactly 125
}
test("ledger projection remains non-negative across randomized terminal operations") {
val store = storeWithRates(now)
val service = service(store, now)
val userId = UUID.randomUUID()
service.grantSignupTrial(userId, 20_000, "property-signup-key")
val random = Random(42)
repeat(100) { index ->
val estimate = random.nextLong(1, 5_000)
val reservation = service.reserve(
userId,
"asr-provider",
"asr-model",
UsageMeasurement.Asr(estimate),
managedCall = false,
idempotencyKey = "property-reserve-$index",
)
if (index % 3 == 0) {
service.release(userId, reservation.id, "property-release-$index")
} else {
val actual = random.nextLong(0, estimate + 1)
service.settle(
userId,
reservation.id,
UsageMeasurement.Asr(actual),
"property-settle-$index",
)
if (index % 5 == 0) {
service.refund(userId, reservation.id, "property-refund-$index")
}
}
}
var projection = 0L
store.ledger.filter { it.userId == userId }.forEach { entry ->
projection = Math.addExact(projection, entry.amountDelta)
entry.balanceAfter shouldBeExactly projection
(projection >= 0) shouldBe true
}
store.balance(userId) shouldBeExactly projection
}
test("campaign cap is consumed once and later qualification is not rewarded") {
val store = storeWithRates(now)
val service = service(store, now)
val campaignId = UUID.randomUUID()
store.campaigns[campaignId] = ReferralCampaign(
id = campaignId,
name = "One reward",
startsAt = now.minusSeconds(60),
endsAt = null,
bindingWindowSeconds = 604_800,
inviterRewardCredits = 7,
inviteeRewardCredits = 5,
maxRewardedBindings = 1,
budgetCredits = 12,
enabled = true,
)
store.campaignBudgets[campaignId] = ReferralCampaignBudget(campaignId, 0, 0, now)
val inviter = UUID.randomUUID()
val invitees = List(2) { UUID.randomUUID() }
invitees.forEach { invitee ->
store.inTransaction {
it.referrals.insertBindingIfAbsent(
ReferralBinding(
id = UUID.randomUUID(),
inviterUserId = inviter,
inviteeUserId = invitee,
codeId = UUID.randomUUID(),
boundAt = now,
rewardedAt = null,
rewardSettlementId = null,
campaignId = campaignId,
),
)
}
service.grantSignupTrial(invitee, 100, "campaign-signup-$invitee")
val reservation = service.reserve(
invitee,
"asr-provider",
"asr-model",
UsageMeasurement.Asr(1_000),
managedCall = true,
idempotencyKey = "campaign-reserve-$invitee",
)
service.settle(
invitee,
reservation.id,
UsageMeasurement.Asr(500),
"campaign-settle-$invitee",
)
}
store.ledger.count {
it.type == LedgerEntryType.REFERRAL_INVITER ||
it.type == LedgerEntryType.REFERRAL_INVITEE
} shouldBe 2
store.campaignBudgets.getValue(campaignId).rewardedBindings shouldBeExactly 1
store.bindings.getValue(invitees[1]).rewardStatus shouldBe
ReferralRewardStatus.INELIGIBLE_BUDGET
}
test("exhausted campaign counters fail closed without partial rewards") {
val store = storeWithRates(now)
val service = service(store, now)
val campaignId = UUID.randomUUID()
store.campaigns[campaignId] = ReferralCampaign(
id = campaignId,
name = "Exhausted",
startsAt = now.minusSeconds(60),
endsAt = null,
bindingWindowSeconds = 604_800,
inviterRewardCredits = 7,
inviteeRewardCredits = 5,
maxRewardedBindings = null,
budgetCredits = null,
enabled = true,
)
store.campaignBudgets[campaignId] = ReferralCampaignBudget(
campaignId,
Long.MAX_VALUE,
Long.MAX_VALUE,
now,
)
val inviter = UUID.randomUUID()
val invitee = UUID.randomUUID()
store.inTransaction {
it.referrals.insertBindingIfAbsent(
ReferralBinding(
id = UUID.randomUUID(),
inviterUserId = inviter,
inviteeUserId = invitee,
codeId = UUID.randomUUID(),
boundAt = now,
rewardedAt = null,
rewardSettlementId = null,
campaignId = campaignId,
),
)
}
service.grantSignupTrial(invitee, 100, "exhausted-signup-key")
val reservation = service.reserve(
invitee,
"asr-provider",
"asr-model",
UsageMeasurement.Asr(1_000),
managedCall = true,
idempotencyKey = "exhausted-reserve-key",
)
service.settle(
invitee,
reservation.id,
UsageMeasurement.Asr(500),
"exhausted-settle-key",
)
store.bindings.getValue(invitee).rewardStatus shouldBe
ReferralRewardStatus.INELIGIBLE_BUDGET
store.ledger.none {
it.type == LedgerEntryType.REFERRAL_INVITER ||
it.type == LedgerEntryType.REFERRAL_INVITEE
} shouldBe true
}
test("account summary reports settled usage separately from remaining credits") {
val store = storeWithRates(now)
val service = service(store, now)
val userId = UUID.randomUUID()
service.grantSignupTrial(userId, 100, "summary-signup-key")
val reservation = service.reserve(
userId,
"asr-provider",
"asr-model",
UsageMeasurement.Asr(1_000),
managedCall = false,
idempotencyKey = "summary-reserve-key",
)
val reservedSummary = service.getAccountSummary(userId)
reservedSummary.account.balance shouldBeExactly 90
reservedSummary.lifetimeUsed shouldBeExactly 0
service.settle(
userId,
reservation.id,
UsageMeasurement.Asr(500),
"summary-settle-key",
)
val summary = service.getAccountSummary(userId)
summary.account.balance shouldBeExactly 95
summary.lifetimeUsed shouldBeExactly 5
service.refund(userId, reservation.id, "summary-refund-key")
val refundedSummary = service.getAccountSummary(userId)
refundedSummary.account.balance shouldBeExactly 100
refundedSummary.lifetimeUsed shouldBeExactly 0
}
test("release and refund restore only the corresponding debit") {
val store = storeWithRates(now)
val service = service(store, now)
val userId = UUID.randomUUID()
service.grantSignupTrial(userId, 100, "signup-key-004")
val released = service.reserve(
userId,
"asr-provider",
"asr-model",
UsageMeasurement.Asr(1_000),
managedCall = false,
idempotencyKey = "reserve-key-004",
)
service.release(userId, released.id, "release-key-004")
service.release(userId, released.id, "release-key-004")
val settled = service.reserve(
userId,
"asr-provider",
"asr-model",
UsageMeasurement.Asr(1_000),
managedCall = false,
idempotencyKey = "reserve-key-005",
)
service.settle(userId, settled.id, UsageMeasurement.Asr(500), "settle-key-005")
service.refund(userId, settled.id, "refund-key-005")
service.refund(userId, settled.id, "refund-key-005")
store.balance(userId) shouldBeExactly 100
store.ledger.filter { it.type == LedgerEntryType.USAGE_RELEASE } shouldHaveSize 1
store.ledger.filter { it.type == LedgerEntryType.USAGE_REFUND } shouldHaveSize 1
}
test("settlement replay rejects different actual usage") {
val store = storeWithRates(now)
val service = service(store, now)
val userId = UUID.randomUUID()
service.grantSignupTrial(userId, 100, "signup-key-006")
val reservation = service.reserve(
userId,
"asr-provider",
"asr-model",
UsageMeasurement.Asr(1_000),
managedCall = false,
idempotencyKey = "reserve-key-006",
)
service.settle(userId, reservation.id, UsageMeasurement.Asr(500), "settle-key-006")
shouldThrow<CreditConflict> {
service.settle(userId, reservation.id, UsageMeasurement.Asr(600), "settle-key-006")
}
}
test("public idempotency values cannot occupy the internal reward namespace") {
externalIdempotencyKey("internal:referral:known-binding:invitee") shouldNotBe
"internal:referral:known-binding:invitee"
}
test("reservation state rules allow only settle release and refund transitions") {
ReservationStateRules.canTransition(
ReservationStatus.RESERVED,
ReservationStatus.SETTLED,
) shouldBe true
ReservationStateRules.canTransition(
ReservationStatus.RESERVED,
ReservationStatus.RELEASED,
) shouldBe true
ReservationStateRules.canTransition(
ReservationStatus.SETTLED,
ReservationStatus.REFUNDED,
) shouldBe true
ReservationStatus.entries.forEach { target ->
ReservationStateRules.canTransition(
ReservationStatus.REFUNDED,
target,
) shouldBe false
}
ReservationStateRules.canTransition(
ReservationStatus.RELEASED,
ReservationStatus.SETTLED,
) shouldBe false
}
})
private fun service(store: TestBillingStore, now: Instant) = CreditService(
transactions = store,
referralRewards = ReferralRewardConfig(inviterCredits = 30, inviteeCredits = 30),
clock = Clock.fixed(now, ZoneOffset.UTC),
)
private fun storeWithRates(now: Instant) = TestBillingStore().also {
val asr = asrRate(now)
val llm = llmRate(now)
it.rates[asr.id] = asr
it.rates[llm.id] = llm
}
private fun asrRate(now: Instant) = CreditRateVersion(
id = UUID.nameUUIDFromBytes("asr-rate".toByteArray()),
kind = UsageKind.ASR,
provider = "asr-provider",
model = "asr-model",
effectiveFrom = now.minusSeconds(60),
effectiveUntil = null,
asrCreditsNumerator = 1,
asrMillisDenominator = 100,
inputCreditsNumerator = null,
inputTokensDenominator = null,
outputCreditsNumerator = null,
outputTokensDenominator = null,
)
private fun llmRate(now: Instant) = CreditRateVersion(
id = UUID.nameUUIDFromBytes("llm-rate".toByteArray()),
kind = UsageKind.LLM,
provider = "llm-provider",
model = "llm-model",
effectiveFrom = now.minusSeconds(60),
effectiveUntil = null,
asrCreditsNumerator = null,
asrMillisDenominator = null,
inputCreditsNumerator = 2,
inputTokensDenominator = 1_000,
outputCreditsNumerator = 3,
outputTokensDenominator = 1_000,
)
private val TEST_OPERATOR_ID = UUID.fromString("11111111-1111-1111-1111-111111111111")