This commit is contained in:
Hanashi committed 2026-08-09 18:48:10 -04:00
1 parent 7f684b26fa
commit 2beefb754b
3 files changed
+88 -80

No files matched your search

@@ -10,7 +10,7 @@
use enums::common::generation::common_resolution::CommonResolution;
use enums::common::generation::common_video_model::CommonVideoModel;
use super::support::{base_generate_request, TestHarness};
use super::support::{base_generate_request, Batch, ExpectedCredits, Seconds, TestHarness};
const STARTING_CREDITS: u64 = 100_000;
@@ -22,31 +22,29 @@ async fn seedance_2p0_charges_by_resolution_duration_and_batch() {
let _serial = mysql_testing::serial::acquire_serial_test_lock().await;
let harness = TestHarness::create().await;
// (resolution, duration seconds, batch count, expected charged credits)
//
// Volcengine rates: 480p 7.772 ¢/s, 720p 16 ¢/s, 1080p 46.632 ¢/s,
// rounded once after duration × batch. Credits = cents.
let cases: &[(Option<CommonResolution>, u16, u16, u64)] = &[
(Some(CommonResolution::FourEightyP), 5, 1, 39),
(Some(CommonResolution::FourEightyP), 10, 1, 78),
(Some(CommonResolution::SevenTwentyP), 5, 1, 80),
(Some(CommonResolution::SevenTwentyP), 10, 1, 160),
(Some(CommonResolution::SevenTwentyP), 15, 1, 240),
(Some(CommonResolution::SevenTwentyP), 5, 2, 160),
(Some(CommonResolution::TenEightyP), 5, 1, 233),
(Some(CommonResolution::TenEightyP), 10, 1, 466),
let cases: &[(Option<CommonResolution>, Seconds, Batch, ExpectedCredits)] = &[
(Some(CommonResolution::FourEightyP), Seconds(5), Batch(1), ExpectedCredits(39)),
(Some(CommonResolution::FourEightyP), Seconds(10), Batch(1), ExpectedCredits(78)),
(Some(CommonResolution::SevenTwentyP), Seconds(5), Batch(1), ExpectedCredits(80)),
(Some(CommonResolution::SevenTwentyP), Seconds(10), Batch(1), ExpectedCredits(160)),
(Some(CommonResolution::SevenTwentyP), Seconds(15), Batch(1), ExpectedCredits(240)),
(Some(CommonResolution::SevenTwentyP), Seconds(5), Batch(2), ExpectedCredits(160)),
(Some(CommonResolution::TenEightyP), Seconds(5), Batch(1), ExpectedCredits(233)),
(Some(CommonResolution::TenEightyP), Seconds(10), Batch(1), ExpectedCredits(466)),
// Default resolution is 720p.
(None, 5, 1, 80),
(None, Seconds(5), Batch(1), ExpectedCredits(80)),
];
for (resolution, duration_seconds, batch_count, expected_credits) in cases {
for (resolution, seconds, batch, expected) in cases {
assert_successful_generation_charges(
&harness,
CommonVideoModel::Seedance2p0,
*resolution,
*duration_seconds,
*batch_count,
*expected_credits,
*seconds,
*batch,
*expected,
)
.await;
}
@@ -59,21 +57,21 @@ async fn seedance_2p0_fast_charges_by_resolution_and_duration() {
let harness = TestHarness::create().await;
// Fast rates: 480p 5.181 ¢/s, 720p 12.727 ¢/s.
let cases: &[(Option<CommonResolution>, u16, u16, u64)] = &[
(Some(CommonResolution::FourEightyP), 5, 1, 26),
(Some(CommonResolution::SevenTwentyP), 5, 1, 64),
(Some(CommonResolution::SevenTwentyP), 10, 1, 127),
(Some(CommonResolution::SevenTwentyP), 5, 2, 127),
let cases: &[(Option<CommonResolution>, Seconds, Batch, ExpectedCredits)] = &[
(Some(CommonResolution::FourEightyP), Seconds(5), Batch(1), ExpectedCredits(26)),
(Some(CommonResolution::SevenTwentyP), Seconds(5), Batch(1), ExpectedCredits(64)),
(Some(CommonResolution::SevenTwentyP), Seconds(10), Batch(1), ExpectedCredits(127)),
(Some(CommonResolution::SevenTwentyP), Seconds(5), Batch(2), ExpectedCredits(127)),
];
for (resolution, duration_seconds, batch_count, expected_credits) in cases {
for (resolution, seconds, batch, expected) in cases {
assert_successful_generation_charges(
&harness,
CommonVideoModel::Seedance2p0Fast,
*resolution,
*duration_seconds,
*batch_count,
*expected_credits,
*seconds,
*batch,
*expected,
)
.await;
}
@@ -92,31 +90,30 @@ async fn byteplus_and_preview_variants_charge_their_own_rates_not_the_base_rate(
let _serial = mysql_testing::serial::acquire_serial_test_lock().await;
let harness = TestHarness::create().await;
// (model, resolution, duration, expected charged credits)
let cases: &[(CommonVideoModel, Option<CommonResolution>, u16, u64)] = &[
let cases: &[(CommonVideoModel, Option<CommonResolution>, Seconds, ExpectedCredits)] = &[
// 720p 5s — the canonical bug shape. 125, NOT 80.
(CommonVideoModel::Seedance2p0BytePlus, Some(CommonResolution::SevenTwentyP), 5, 125),
(CommonVideoModel::Seedance2p0BytePlusUltra, Some(CommonResolution::SevenTwentyP), 5, 125),
(CommonVideoModel::PreviewModel, Some(CommonResolution::SevenTwentyP), 5, 125),
(CommonVideoModel::Seedance2p0BytePlus, Some(CommonResolution::SevenTwentyP), Seconds(5), ExpectedCredits(125)),
(CommonVideoModel::Seedance2p0BytePlusUltra, Some(CommonResolution::SevenTwentyP), Seconds(5), ExpectedCredits(125)),
(CommonVideoModel::PreviewModel, Some(CommonResolution::SevenTwentyP), Seconds(5), ExpectedCredits(125)),
// Fast 720p 5s: 100, NOT 64.
(CommonVideoModel::Seedance2p0BytePlusFast, Some(CommonResolution::SevenTwentyP), 5, 100),
(CommonVideoModel::Seedance2p0BytePlusUltraFast, Some(CommonResolution::SevenTwentyP), 5, 100),
(CommonVideoModel::PreviewModelFast, Some(CommonResolution::SevenTwentyP), 5, 100),
(CommonVideoModel::Seedance2p0BytePlusFast, Some(CommonResolution::SevenTwentyP), Seconds(5), ExpectedCredits(100)),
(CommonVideoModel::Seedance2p0BytePlusUltraFast, Some(CommonResolution::SevenTwentyP), Seconds(5), ExpectedCredits(100)),
(CommonVideoModel::PreviewModelFast, Some(CommonResolution::SevenTwentyP), Seconds(5), ExpectedCredits(100)),
// Other resolutions and durations hold too.
(CommonVideoModel::Seedance2p0BytePlusUltra, Some(CommonResolution::FourEightyP), 5, 50),
(CommonVideoModel::Seedance2p0BytePlusUltra, Some(CommonResolution::TenEightyP), 5, 250),
(CommonVideoModel::Seedance2p0BytePlusUltra, Some(CommonResolution::SevenTwentyP), 10, 250),
(CommonVideoModel::Seedance2p0BytePlusUltraFast, Some(CommonResolution::FourEightyP), 10, 90),
(CommonVideoModel::Seedance2p0BytePlusUltra, Some(CommonResolution::FourEightyP), Seconds(5), ExpectedCredits(50)),
(CommonVideoModel::Seedance2p0BytePlusUltra, Some(CommonResolution::TenEightyP), Seconds(5), ExpectedCredits(250)),
(CommonVideoModel::Seedance2p0BytePlusUltra, Some(CommonResolution::SevenTwentyP), Seconds(10), ExpectedCredits(250)),
(CommonVideoModel::Seedance2p0BytePlusUltraFast, Some(CommonResolution::FourEightyP), Seconds(10), ExpectedCredits(90)),
];
for (model, resolution, duration_seconds, expected_credits) in cases {
for (model, resolution, seconds, expected) in cases {
assert_successful_generation_charges(
&harness,
*model,
*resolution,
*duration_seconds,
1,
*expected_credits,
*seconds,
Batch(1),
*expected,
)
.await;
}
@@ -150,15 +147,15 @@ async fn insufficient_balance_is_a_402_and_charges_nothing() {
// ── Shared assertion ──
/// Fund a fresh user, run one generation to completion via the stub Kinovi
/// server, and assert the wallet was debited exactly `expected_credits`
/// server, and assert the wallet was debited exactly the expected credits
/// (balance delta AND ledger entry).
async fn assert_successful_generation_charges(
harness: &TestHarness,
model: CommonVideoModel,
resolution: Option<CommonResolution>,
duration_seconds: u16,
batch_count: u16,
expected_credits: u64,
Seconds(duration_seconds): Seconds,
Batch(batch_count): Batch,
ExpectedCredits(expected_credits): ExpectedCredits,
) {
let user = harness.create_funded_user(STARTING_CREDITS).await;
@@ -12,7 +12,7 @@
use enums::common::generation::common_resolution::CommonResolution;
use enums::common::generation::common_video_model::CommonVideoModel;
use super::support::{base_generate_request, TestHarness};
use super::support::{base_generate_request, ExpectedCredits, Seconds, TestHarness};
const STARTING_CREDITS: u64 = 100_000;
@@ -26,25 +26,25 @@ async fn seedance_2p5_charges_by_resolution_and_duration() {
// 2.5 rates: 480p 11.76954733 ¢/s, 720p 26.70781893 ¢/s, ceil-rounded.
// Only 480p/720p exist; 1080p downgrades to 720p pricing. No batching.
let cases: &[(Option<CommonResolution>, u16, u64)] = &[
(Some(CommonResolution::FourEightyP), 4, 48),
(Some(CommonResolution::FourEightyP), 5, 59),
(Some(CommonResolution::FourEightyP), 30, 354),
(Some(CommonResolution::SevenTwentyP), 4, 107),
(Some(CommonResolution::SevenTwentyP), 5, 134),
(Some(CommonResolution::SevenTwentyP), 10, 268),
(Some(CommonResolution::SevenTwentyP), 30, 802),
let cases: &[(Option<CommonResolution>, Seconds, ExpectedCredits)] = &[
(Some(CommonResolution::FourEightyP), Seconds(4), ExpectedCredits(48)),
(Some(CommonResolution::FourEightyP), Seconds(5), ExpectedCredits(59)),
(Some(CommonResolution::FourEightyP), Seconds(30), ExpectedCredits(354)),
(Some(CommonResolution::SevenTwentyP), Seconds(4), ExpectedCredits(107)),
(Some(CommonResolution::SevenTwentyP), Seconds(5), ExpectedCredits(134)),
(Some(CommonResolution::SevenTwentyP), Seconds(10), ExpectedCredits(268)),
(Some(CommonResolution::SevenTwentyP), Seconds(30), ExpectedCredits(802)),
// Default resolution is 720p.
(None, 5, 134),
(None, Seconds(5), ExpectedCredits(134)),
];
for (resolution, duration_seconds, expected_credits) in cases {
for (resolution, seconds, expected) in cases {
assert_successful_generation_charges(
&harness,
CommonVideoModel::Seedance2p5,
*resolution,
*duration_seconds,
*expected_credits,
*seconds,
*expected,
)
.await;
}
@@ -60,21 +60,21 @@ async fn seedance_2p5_ultra_charges_its_own_higher_rates() {
let harness = TestHarness::create().await;
// Ultra rates: 480p 13.90946502 ¢/s, 720p 31.56378601 ¢/s, ceil-rounded.
let cases: &[(Option<CommonResolution>, u16, u64)] = &[
(Some(CommonResolution::FourEightyP), 5, 70), // regular would be 59
(Some(CommonResolution::FourEightyP), 30, 418), // regular would be 354
(Some(CommonResolution::SevenTwentyP), 5, 158), // regular would be 134
(Some(CommonResolution::SevenTwentyP), 30, 947), // regular would be 802
(None, 5, 158),
let cases: &[(Option<CommonResolution>, Seconds, ExpectedCredits)] = &[
(Some(CommonResolution::FourEightyP), Seconds(5), ExpectedCredits(70)), // regular would be 59
(Some(CommonResolution::FourEightyP), Seconds(30), ExpectedCredits(418)), // regular would be 354
(Some(CommonResolution::SevenTwentyP), Seconds(5), ExpectedCredits(158)), // regular would be 134
(Some(CommonResolution::SevenTwentyP), Seconds(30), ExpectedCredits(947)), // regular would be 802
(None, Seconds(5), ExpectedCredits(158)),
];
for (resolution, duration_seconds, expected_credits) in cases {
for (resolution, seconds, expected) in cases {
assert_successful_generation_charges(
&harness,
CommonVideoModel::Seedance2p5Ultra,
*resolution,
*duration_seconds,
*expected_credits,
*seconds,
*expected,
)
.await;
}
@@ -96,20 +96,20 @@ async fn seedance_2p5_bills_reference_video_input_seconds_at_worst_case_when_unp
let _serial = mysql_testing::serial::acquire_serial_test_lock().await;
let harness = TestHarness::create().await;
let cases: &[(CommonVideoModel, Option<CommonResolution>, u16, u64)] = &[
(CommonVideoModel::Seedance2p5, Some(CommonResolution::FourEightyP), 30, 435),
(CommonVideoModel::Seedance2p5, Some(CommonResolution::SevenTwentyP), 30, 951),
(CommonVideoModel::Seedance2p5Ultra, Some(CommonResolution::FourEightyP), 30, 514),
(CommonVideoModel::Seedance2p5Ultra, Some(CommonResolution::SevenTwentyP), 30, 1124),
let cases: &[(CommonVideoModel, Option<CommonResolution>, Seconds, ExpectedCredits)] = &[
(CommonVideoModel::Seedance2p5, Some(CommonResolution::FourEightyP), Seconds(30), ExpectedCredits(435)),
(CommonVideoModel::Seedance2p5, Some(CommonResolution::SevenTwentyP), Seconds(30), ExpectedCredits(951)),
(CommonVideoModel::Seedance2p5Ultra, Some(CommonResolution::FourEightyP), Seconds(30), ExpectedCredits(514)),
(CommonVideoModel::Seedance2p5Ultra, Some(CommonResolution::SevenTwentyP), Seconds(30), ExpectedCredits(1124)),
];
for (model, resolution, duration_seconds, expected_credits) in cases {
for (model, resolution, seconds, expected) in cases {
assert_reference_video_charge_then_refund(
&harness,
*model,
*resolution,
*duration_seconds,
*expected_credits,
*seconds,
*expected,
)
.await;
}
@@ -123,8 +123,8 @@ async fn assert_successful_generation_charges(
harness: &TestHarness,
model: CommonVideoModel,
resolution: Option<CommonResolution>,
duration_seconds: u16,
expected_credits: u64,
Seconds(duration_seconds): Seconds,
ExpectedCredits(expected_credits): ExpectedCredits,
) {
let user = harness.create_funded_user(STARTING_CREDITS).await;
@@ -156,8 +156,8 @@ async fn assert_reference_video_charge_then_refund(
harness: &TestHarness,
model: CommonVideoModel,
resolution: Option<CommonResolution>,
duration_seconds: u16,
expected_credits: u64,
Seconds(duration_seconds): Seconds,
ExpectedCredits(expected_credits): ExpectedCredits,
) {
let user = harness.create_funded_user(STARTING_CREDITS).await;
@@ -170,6 +170,17 @@ impl TestHarness {
}
}
/// Newtype wrappers so pricing-table test cases read unambiguously:
/// `(Some(FourEightyP), Seconds(5), Batch(1), ExpectedCredits(39))`.
#[derive(Clone, Copy, Debug)]
pub struct Seconds(pub u16);
#[derive(Clone, Copy, Debug)]
pub struct Batch(pub u16);
#[derive(Clone, Copy, Debug)]
pub struct ExpectedCredits(pub u64);
/// A generate request with only the model set; tests fill in the rest.
/// Idempotency tokens must be unique per call.
pub fn base_generate_request(model: CommonVideoModel) -> OmniGenVideoCostAndGenerateRequest {