mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-31 15:37:49 +00:00
newtype
This commit is contained in:
1 parent
7f684b26fa
commit
2beefb754b
3 files changed
+88
-80
No files matched your search
+43
-46
@@ -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;
|
||||
|
||||
|
||||
+34
-34
@@ -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;
|
||||
|
||||
|
||||
+11
@@ -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 {
|
||||
|
||||
Reference in new issue
Block a user