From ac6a69fa32cba06f3d34b82ecbfe4e8ace45da81 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Sun, 8 Mar 2026 14:23:33 -0400 Subject: [PATCH] enhance tests --- ...ue_kling_3p0_pro_image_to_video_webhook.rs | 103 +++++++++--- ...ing_3p0_standard_image_to_video_webhook.rs | 102 +++++++++--- ...eue_kling_3p0_pro_text_to_video_webhook.rs | 143 +++++++++++----- ...ling_3p0_standard_text_to_video_webhook.rs | 157 +++++++++++------- 4 files changed, 361 insertions(+), 144 deletions(-) diff --git a/crates/api_clients/fal_client/src/requests/webhook/video/image/enqueue_kling_3p0_pro_image_to_video_webhook.rs b/crates/api_clients/fal_client/src/requests/webhook/video/image/enqueue_kling_3p0_pro_image_to_video_webhook.rs index 9f65a2d866..b9bbc29bee 100644 --- a/crates/api_clients/fal_client/src/requests/webhook/video/image/enqueue_kling_3p0_pro_image_to_video_webhook.rs +++ b/crates/api_clients/fal_client/src/requests/webhook/video/image/enqueue_kling_3p0_pro_image_to_video_webhook.rs @@ -75,38 +75,97 @@ pub async fn enqueue_kling_3p0_pro_image_to_video_webhook( #[cfg(test)] mod tests { use super::*; + use crate::creds::fal_api_key::FalApiKey; + use crate::requests::traits::fal_request_cost_calculator_trait::FalRequestCostCalculator; + use errors::AnyhowResult; + use std::fs::read_to_string; + use strum::IntoEnumIterator; + use test_data::web::image_urls::TREX_SKELETON_IMAGE_URL; #[test] - fn test_cost_pro_i2v_audio_off_5s() { + fn test_cost() { let api_key = FalApiKey::from_str(""); - let args = EnqueueKling3p0ProImageToVideoArgs { - prompt: String::new(), - image_url: String::new(), + + let mut args = EnqueueKling3p0ProImageToVideoArgs { + prompt: "the t-rex skeleton leaps off the podium and charges".to_string(), + image_url: TREX_SKELETON_IMAGE_URL.to_string(), end_image_url: None, generate_audio: Some(false), negative_prompt: None, duration: Some(EnqueueKling3p0ProTextToVideoDuration::FiveSeconds), - webhook_url: "https://example.com", + webhook_url: "https://example.com/webhook", api_key: &api_key, }; - // $0.224 * 5 = $1.12 = 112 cents - assert_eq!(args.calculate_cost_in_cents(), 112); - } - #[test] - fn test_cost_pro_i2v_audio_on_10s() { - let api_key = FalApiKey::from_str(""); - let args = EnqueueKling3p0ProImageToVideoArgs { - prompt: String::new(), - image_url: String::new(), - end_image_url: None, - generate_audio: Some(true), - negative_prompt: None, - duration: Some(EnqueueKling3p0ProTextToVideoDuration::TenSeconds), - webhook_url: "https://example.com", - api_key: &api_key, - }; - // $0.336 * 10 = $3.36 = 336 cents + // Audio off: $0.224/sec + // 5s: (224 * 5 + 9) / 10 = 1129 / 10 = 112 + assert_eq!(args.calculate_cost_in_cents(), 112); + + // 10s: (224 * 10 + 9) / 10 = 2249 / 10 = 224 + args.duration = Some(EnqueueKling3p0ProTextToVideoDuration::TenSeconds); + assert_eq!(args.calculate_cost_in_cents(), 224); + + // 15s: (224 * 15 + 9) / 10 = 3369 / 10 = 336 + args.duration = Some(EnqueueKling3p0ProTextToVideoDuration::FifteenSeconds); + assert_eq!(args.calculate_cost_in_cents(), 336); + + // Audio on: $0.336/sec + args.generate_audio = Some(true); + + // 5s: (336 * 5 + 9) / 10 = 1689 / 10 = 168 + args.duration = Some(EnqueueKling3p0ProTextToVideoDuration::FiveSeconds); + assert_eq!(args.calculate_cost_in_cents(), 168); + + // 10s: (336 * 10 + 9) / 10 = 3369 / 10 = 336 + args.duration = Some(EnqueueKling3p0ProTextToVideoDuration::TenSeconds); assert_eq!(args.calculate_cost_in_cents(), 336); } + + #[tokio::test] + #[ignore] // manually run — fires a real API request and incurs cost + async fn test() -> AnyhowResult<()> { + let secret = read_to_string("/Users/bt/Artcraft/credentials/fal_api_key.txt")?; + let api_key = FalApiKey::from_str(&secret); + + let args = EnqueueKling3p0ProImageToVideoArgs { + image_url: TREX_SKELETON_IMAGE_URL.to_string(), + prompt: "the t-rex skeleton gets off the podium and begins walking to the camera, then bites".to_string(), + duration: Some(EnqueueKling3p0ProTextToVideoDuration::FiveSeconds), + generate_audio: Some(true), + negative_prompt: None, + end_image_url: None, + api_key: &api_key, + webhook_url: "https://example.com/webhook", + }; + + let result = enqueue_kling_3p0_pro_image_to_video_webhook(args).await?; + println!("result: {:?}", result); + + Ok(()) + } + + #[tokio::test] + #[ignore] // manually run — fires a real API request per variant (expensive) + async fn test_all_durations() -> AnyhowResult<()> { + let secret = read_to_string("/Users/bt/Artcraft/credentials/fal_api_key.txt")?; + let api_key = FalApiKey::from_str(&secret); + + for dur in EnqueueKling3p0ProTextToVideoDuration::iter() { + println!("--- duration: {:?} ---", dur); + let args = EnqueueKling3p0ProImageToVideoArgs { + image_url: TREX_SKELETON_IMAGE_URL.to_string(), + prompt: "the skeleton slowly turns its head and roars".to_string(), + duration: Some(dur), + generate_audio: Some(false), + negative_prompt: None, + end_image_url: None, + api_key: &api_key, + webhook_url: "https://example.com/webhook", + }; + let result = enqueue_kling_3p0_pro_image_to_video_webhook(args).await?; + println!("result: {:?}", result); + } + + Ok(()) + } } diff --git a/crates/api_clients/fal_client/src/requests/webhook/video/image/enqueue_kling_3p0_standard_image_to_video_webhook.rs b/crates/api_clients/fal_client/src/requests/webhook/video/image/enqueue_kling_3p0_standard_image_to_video_webhook.rs index c5c3b1b4c0..8c4b1dc932 100644 --- a/crates/api_clients/fal_client/src/requests/webhook/video/image/enqueue_kling_3p0_standard_image_to_video_webhook.rs +++ b/crates/api_clients/fal_client/src/requests/webhook/video/image/enqueue_kling_3p0_standard_image_to_video_webhook.rs @@ -68,37 +68,97 @@ pub async fn enqueue_kling_3p0_standard_image_to_video_webhook( #[cfg(test)] mod tests { use super::*; + use crate::creds::fal_api_key::FalApiKey; + use crate::requests::traits::fal_request_cost_calculator_trait::FalRequestCostCalculator; + use errors::AnyhowResult; + use std::fs::read_to_string; + use strum::IntoEnumIterator; + use test_data::web::image_urls::TREX_SKELETON_IMAGE_URL; #[test] - fn test_cost_standard_i2v_audio_off_5s() { + fn test_cost() { let api_key = FalApiKey::from_str(""); - let args = EnqueueKling3p0StandardImageToVideoArgs { - prompt: String::new(), - image_url: String::new(), + + let mut args = EnqueueKling3p0StandardImageToVideoArgs { + prompt: "the t-rex skeleton comes alive and roars".to_string(), + image_url: TREX_SKELETON_IMAGE_URL.to_string(), end_image_url: None, generate_audio: Some(false), negative_prompt: None, duration: Some(EnqueueKling3p0StandardTextToVideoDuration::FiveSeconds), - webhook_url: "https://example.com", + webhook_url: "https://example.com/webhook", api_key: &api_key, }; - assert_eq!(args.calculate_cost_in_cents(), 84); - } - #[test] - fn test_cost_standard_i2v_audio_on_10s() { - let api_key = FalApiKey::from_str(""); - let args = EnqueueKling3p0StandardImageToVideoArgs { - prompt: String::new(), - image_url: String::new(), - end_image_url: None, - generate_audio: Some(true), - negative_prompt: None, - duration: Some(EnqueueKling3p0StandardTextToVideoDuration::TenSeconds), - webhook_url: "https://example.com", - api_key: &api_key, - }; - // $0.252 * 10 = $2.52 = 252 cents + // Audio off: $0.168/sec + // 5s: (168 * 5 + 9) / 10 = 849 / 10 = 84 + assert_eq!(args.calculate_cost_in_cents(), 84); + + // 10s: (168 * 10 + 9) / 10 = 1689 / 10 = 168 + args.duration = Some(EnqueueKling3p0StandardTextToVideoDuration::TenSeconds); + assert_eq!(args.calculate_cost_in_cents(), 168); + + // 15s: (168 * 15 + 9) / 10 = 2529 / 10 = 252 + args.duration = Some(EnqueueKling3p0StandardTextToVideoDuration::FifteenSeconds); + assert_eq!(args.calculate_cost_in_cents(), 252); + + // Audio on: $0.252/sec + args.generate_audio = Some(true); + + // 5s: (252 * 5 + 9) / 10 = 1269 / 10 = 126 + args.duration = Some(EnqueueKling3p0StandardTextToVideoDuration::FiveSeconds); + assert_eq!(args.calculate_cost_in_cents(), 126); + + // 10s: (252 * 10 + 9) / 10 = 2529 / 10 = 252 + args.duration = Some(EnqueueKling3p0StandardTextToVideoDuration::TenSeconds); assert_eq!(args.calculate_cost_in_cents(), 252); } + + #[tokio::test] + #[ignore] // manually run — fires a real API request and incurs cost + async fn test() -> AnyhowResult<()> { + let secret = read_to_string("/Users/bt/Artcraft/credentials/fal_api_key.txt")?; + let api_key = FalApiKey::from_str(&secret); + + let args = EnqueueKling3p0StandardImageToVideoArgs { + image_url: TREX_SKELETON_IMAGE_URL.to_string(), + prompt: "the t-rex skeleton gets off the podium and begins walking toward the camera".to_string(), + duration: Some(EnqueueKling3p0StandardTextToVideoDuration::FiveSeconds), + generate_audio: Some(true), + negative_prompt: None, + end_image_url: None, + api_key: &api_key, + webhook_url: "https://example.com/webhook", + }; + + let result = enqueue_kling_3p0_standard_image_to_video_webhook(args).await?; + println!("result: {:?}", result); + + Ok(()) + } + + #[tokio::test] + #[ignore] // manually run — fires a real API request per variant (expensive) + async fn test_all_durations() -> AnyhowResult<()> { + let secret = read_to_string("/Users/bt/Artcraft/credentials/fal_api_key.txt")?; + let api_key = FalApiKey::from_str(&secret); + + for dur in EnqueueKling3p0StandardTextToVideoDuration::iter() { + println!("--- duration: {:?} ---", dur); + let args = EnqueueKling3p0StandardImageToVideoArgs { + image_url: TREX_SKELETON_IMAGE_URL.to_string(), + prompt: "the skeleton slowly turns its head and opens its jaw".to_string(), + duration: Some(dur), + generate_audio: Some(false), + negative_prompt: None, + end_image_url: None, + api_key: &api_key, + webhook_url: "https://example.com/webhook", + }; + let result = enqueue_kling_3p0_standard_image_to_video_webhook(args).await?; + println!("result: {:?}", result); + } + + Ok(()) + } } diff --git a/crates/api_clients/fal_client/src/requests/webhook/video/text/enqueue_kling_3p0_pro_text_to_video_webhook.rs b/crates/api_clients/fal_client/src/requests/webhook/video/text/enqueue_kling_3p0_pro_text_to_video_webhook.rs index f13e3cb872..8539b75e5f 100644 --- a/crates/api_clients/fal_client/src/requests/webhook/video/text/enqueue_kling_3p0_pro_text_to_video_webhook.rs +++ b/crates/api_clients/fal_client/src/requests/webhook/video/text/enqueue_kling_3p0_pro_text_to_video_webhook.rs @@ -20,7 +20,7 @@ pub struct EnqueueKling3p0ProTextToVideoArgs<'a, R: IntoUrl> { pub api_key: &'a FalApiKey, } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::EnumIter)] pub enum EnqueueKling3p0ProTextToVideoDuration { ThreeSeconds, FourSeconds, @@ -75,7 +75,7 @@ impl EnqueueKling3p0ProTextToVideoDuration { } } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::EnumIter)] pub enum EnqueueKling3p0ProTextToVideoAspectRatio { Square, SixteenByNine, @@ -134,68 +134,125 @@ pub async fn enqueue_kling_3p0_pro_text_to_video_webhook( #[cfg(test)] mod tests { use super::*; + use crate::creds::fal_api_key::FalApiKey; + use crate::requests::traits::fal_request_cost_calculator_trait::FalRequestCostCalculator; + use errors::AnyhowResult; + use std::fs::read_to_string; + use strum::IntoEnumIterator; #[test] - fn test_cost_pro_audio_off_5s() { + fn test_cost() { let api_key = FalApiKey::from_str(""); - let args = EnqueueKling3p0ProTextToVideoArgs { - prompt: String::new(), + + let mut args = EnqueueKling3p0ProTextToVideoArgs { + prompt: "a spacecraft drifts through an asteroid field, dramatic lighting".to_string(), generate_audio: Some(false), negative_prompt: None, duration: Some(EnqueueKling3p0ProTextToVideoDuration::FiveSeconds), aspect_ratio: None, - webhook_url: "https://example.com", + webhook_url: "https://example.com/webhook", api_key: &api_key, }; - // $0.224 * 5 = $1.12 = 112 cents + + // Audio off: $0.224/sec + // 5s: (224 * 5 + 9) / 10 = 1129 / 10 = 112 assert_eq!(args.calculate_cost_in_cents(), 112); + + // 3s: (224 * 3 + 9) / 10 = 681 / 10 = 68 + args.duration = Some(EnqueueKling3p0ProTextToVideoDuration::ThreeSeconds); + assert_eq!(args.calculate_cost_in_cents(), 68); + + // 10s: (224 * 10 + 9) / 10 = 2249 / 10 = 224 + args.duration = Some(EnqueueKling3p0ProTextToVideoDuration::TenSeconds); + assert_eq!(args.calculate_cost_in_cents(), 224); + + // 15s: (224 * 15 + 9) / 10 = 3369 / 10 = 336 + args.duration = Some(EnqueueKling3p0ProTextToVideoDuration::FifteenSeconds); + assert_eq!(args.calculate_cost_in_cents(), 336); + + // Audio on: $0.336/sec + args.generate_audio = Some(true); + + // 5s: (336 * 5 + 9) / 10 = 1689 / 10 = 168 + args.duration = Some(EnqueueKling3p0ProTextToVideoDuration::FiveSeconds); + assert_eq!(args.calculate_cost_in_cents(), 168); + + // 10s: (336 * 10 + 9) / 10 = 3369 / 10 = 336 + args.duration = Some(EnqueueKling3p0ProTextToVideoDuration::TenSeconds); + assert_eq!(args.calculate_cost_in_cents(), 336); + + // 15s: (336 * 15 + 9) / 10 = 5049 / 10 = 504 + args.duration = Some(EnqueueKling3p0ProTextToVideoDuration::FifteenSeconds); + assert_eq!(args.calculate_cost_in_cents(), 504); } - #[test] - fn test_cost_pro_audio_on_5s() { - let api_key = FalApiKey::from_str(""); + #[tokio::test] + #[ignore] // manually run — fires a real API request and incurs cost + async fn test() -> AnyhowResult<()> { + let secret = read_to_string("/Users/bt/Artcraft/credentials/fal_api_key.txt")?; + let api_key = FalApiKey::from_str(&secret); + let args = EnqueueKling3p0ProTextToVideoArgs { - prompt: String::new(), + prompt: "a samurai draws a katana in a bamboo forest, cherry blossoms falling in slow motion".to_string(), generate_audio: Some(true), negative_prompt: None, duration: Some(EnqueueKling3p0ProTextToVideoDuration::FiveSeconds), - aspect_ratio: None, - webhook_url: "https://example.com", + aspect_ratio: Some(EnqueueKling3p0ProTextToVideoAspectRatio::SixteenByNine), api_key: &api_key, + webhook_url: "https://example.com/webhook", }; - // $0.336 * 5 = $1.68 = 168 cents - assert_eq!(args.calculate_cost_in_cents(), 168); + + let result = enqueue_kling_3p0_pro_text_to_video_webhook(args).await?; + println!("result: {:?}", result); + + Ok(()) } - #[test] - fn test_cost_pro_audio_off_10s() { - let api_key = FalApiKey::from_str(""); - let args = EnqueueKling3p0ProTextToVideoArgs { - prompt: String::new(), - generate_audio: Some(false), - negative_prompt: None, - duration: Some(EnqueueKling3p0ProTextToVideoDuration::TenSeconds), - aspect_ratio: None, - webhook_url: "https://example.com", - api_key: &api_key, - }; - // $0.224 * 10 = $2.24 = 224 cents - assert_eq!(args.calculate_cost_in_cents(), 224); + #[tokio::test] + #[ignore] // manually run — fires a real API request per variant (expensive) + async fn test_all_aspect_ratios() -> AnyhowResult<()> { + let secret = read_to_string("/Users/bt/Artcraft/credentials/fal_api_key.txt")?; + let api_key = FalApiKey::from_str(&secret); + + for ar in EnqueueKling3p0ProTextToVideoAspectRatio::iter() { + println!("--- aspect ratio: {:?} ---", ar); + let args = EnqueueKling3p0ProTextToVideoArgs { + prompt: "a hot air balloon rises over misty mountains at dawn".to_string(), + generate_audio: Some(true), + negative_prompt: None, + duration: Some(EnqueueKling3p0ProTextToVideoDuration::ThreeSeconds), + aspect_ratio: Some(ar), + api_key: &api_key, + webhook_url: "https://example.com/webhook", + }; + let result = enqueue_kling_3p0_pro_text_to_video_webhook(args).await?; + println!("result: {:?}", result); + } + + Ok(()) } - #[test] - fn test_cost_pro_audio_off_15s() { - let api_key = FalApiKey::from_str(""); - let args = EnqueueKling3p0ProTextToVideoArgs { - prompt: String::new(), - generate_audio: Some(false), - negative_prompt: None, - duration: Some(EnqueueKling3p0ProTextToVideoDuration::FifteenSeconds), - aspect_ratio: None, - webhook_url: "https://example.com", - api_key: &api_key, - }; - // $0.224 * 15 = $3.36 = 336 cents - assert_eq!(args.calculate_cost_in_cents(), 336); + #[tokio::test] + #[ignore] // manually run — fires a real API request per variant (expensive) + async fn test_all_durations() -> AnyhowResult<()> { + let secret = read_to_string("/Users/bt/Artcraft/credentials/fal_api_key.txt")?; + let api_key = FalApiKey::from_str(&secret); + + for dur in EnqueueKling3p0ProTextToVideoDuration::iter() { + println!("--- duration: {:?} ---", dur); + let args = EnqueueKling3p0ProTextToVideoArgs { + prompt: "a lighthouse beam sweeps across a stormy sea at night".to_string(), + generate_audio: Some(false), + negative_prompt: None, + duration: Some(dur), + aspect_ratio: Some(EnqueueKling3p0ProTextToVideoAspectRatio::SixteenByNine), + api_key: &api_key, + webhook_url: "https://example.com/webhook", + }; + let result = enqueue_kling_3p0_pro_text_to_video_webhook(args).await?; + println!("result: {:?}", result); + } + + Ok(()) } } diff --git a/crates/api_clients/fal_client/src/requests/webhook/video/text/enqueue_kling_3p0_standard_text_to_video_webhook.rs b/crates/api_clients/fal_client/src/requests/webhook/video/text/enqueue_kling_3p0_standard_text_to_video_webhook.rs index 81eb408c63..196e6a85a4 100644 --- a/crates/api_clients/fal_client/src/requests/webhook/video/text/enqueue_kling_3p0_standard_text_to_video_webhook.rs +++ b/crates/api_clients/fal_client/src/requests/webhook/video/text/enqueue_kling_3p0_standard_text_to_video_webhook.rs @@ -20,7 +20,7 @@ pub struct EnqueueKling3p0StandardTextToVideoArgs<'a, R: IntoUrl> { pub api_key: &'a FalApiKey, } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::EnumIter)] pub enum EnqueueKling3p0StandardTextToVideoDuration { ThreeSeconds, FourSeconds, @@ -75,7 +75,7 @@ impl EnqueueKling3p0StandardTextToVideoDuration { } } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::EnumIter)] pub enum EnqueueKling3p0StandardTextToVideoAspectRatio { Square, SixteenByNine, @@ -135,84 +135,125 @@ pub async fn enqueue_kling_3p0_standard_text_to_video_webhook( #[cfg(test)] mod tests { use super::*; + use crate::creds::fal_api_key::FalApiKey; + use crate::requests::traits::fal_request_cost_calculator_trait::FalRequestCostCalculator; + use errors::AnyhowResult; + use std::fs::read_to_string; + use strum::IntoEnumIterator; #[test] - fn test_cost_standard_audio_off() { + fn test_cost() { let api_key = FalApiKey::from_str(""); - let args = EnqueueKling3p0StandardTextToVideoArgs { - prompt: String::new(), + + let mut args = EnqueueKling3p0StandardTextToVideoArgs { + prompt: "a cat sitting on a windowsill watching rain".to_string(), generate_audio: Some(false), negative_prompt: None, duration: Some(EnqueueKling3p0StandardTextToVideoDuration::FiveSeconds), aspect_ratio: None, - webhook_url: "https://example.com", + webhook_url: "https://example.com/webhook", api_key: &api_key, }; - // $0.168 * 5 = $0.84 = 84 cents + + // Audio off: $0.168/sec + // 5s: (168 * 5 + 9) / 10 = 849 / 10 = 84 assert_eq!(args.calculate_cost_in_cents(), 84); + + // 3s: (168 * 3 + 9) / 10 = 513 / 10 = 51 + args.duration = Some(EnqueueKling3p0StandardTextToVideoDuration::ThreeSeconds); + assert_eq!(args.calculate_cost_in_cents(), 51); + + // 10s: (168 * 10 + 9) / 10 = 1689 / 10 = 168 + args.duration = Some(EnqueueKling3p0StandardTextToVideoDuration::TenSeconds); + assert_eq!(args.calculate_cost_in_cents(), 168); + + // 15s: (168 * 15 + 9) / 10 = 2529 / 10 = 252 + args.duration = Some(EnqueueKling3p0StandardTextToVideoDuration::FifteenSeconds); + assert_eq!(args.calculate_cost_in_cents(), 252); + + // Audio on: $0.252/sec + args.generate_audio = Some(true); + + // 5s: (252 * 5 + 9) / 10 = 1269 / 10 = 126 + args.duration = Some(EnqueueKling3p0StandardTextToVideoDuration::FiveSeconds); + assert_eq!(args.calculate_cost_in_cents(), 126); + + // 10s: (252 * 10 + 9) / 10 = 2529 / 10 = 252 + args.duration = Some(EnqueueKling3p0StandardTextToVideoDuration::TenSeconds); + assert_eq!(args.calculate_cost_in_cents(), 252); + + // 15s: (252 * 15 + 9) / 10 = 3789 / 10 = 378 + args.duration = Some(EnqueueKling3p0StandardTextToVideoDuration::FifteenSeconds); + assert_eq!(args.calculate_cost_in_cents(), 378); } - #[test] - fn test_cost_standard_audio_on() { - let api_key = FalApiKey::from_str(""); + #[tokio::test] + #[ignore] // manually run — fires a real API request and incurs cost + async fn test() -> AnyhowResult<()> { + let secret = read_to_string("/Users/bt/Artcraft/credentials/fal_api_key.txt")?; + let api_key = FalApiKey::from_str(&secret); + let args = EnqueueKling3p0StandardTextToVideoArgs { - prompt: String::new(), + prompt: "a golden retriever puppy chases butterflies through a sunlit meadow, cinematic slow motion".to_string(), generate_audio: Some(true), negative_prompt: None, duration: Some(EnqueueKling3p0StandardTextToVideoDuration::FiveSeconds), - aspect_ratio: None, - webhook_url: "https://example.com", + aspect_ratio: Some(EnqueueKling3p0StandardTextToVideoAspectRatio::SixteenByNine), api_key: &api_key, + webhook_url: "https://example.com/webhook", }; - // $0.252 * 5 = $1.26 = 126 cents - assert_eq!(args.calculate_cost_in_cents(), 126); + + let result = enqueue_kling_3p0_standard_text_to_video_webhook(args).await?; + println!("result: {:?}", result); + + Ok(()) } - #[test] - fn test_cost_standard_audio_off_10s() { - let api_key = FalApiKey::from_str(""); - let args = EnqueueKling3p0StandardTextToVideoArgs { - prompt: String::new(), - generate_audio: Some(false), - negative_prompt: None, - duration: Some(EnqueueKling3p0StandardTextToVideoDuration::TenSeconds), - aspect_ratio: None, - webhook_url: "https://example.com", - api_key: &api_key, - }; - // $0.168 * 10 = $1.68 = 168 cents - assert_eq!(args.calculate_cost_in_cents(), 168); + #[tokio::test] + #[ignore] // manually run — fires a real API request per variant (expensive) + async fn test_all_aspect_ratios() -> AnyhowResult<()> { + let secret = read_to_string("/Users/bt/Artcraft/credentials/fal_api_key.txt")?; + let api_key = FalApiKey::from_str(&secret); + + for ar in EnqueueKling3p0StandardTextToVideoAspectRatio::iter() { + println!("--- aspect ratio: {:?} ---", ar); + let args = EnqueueKling3p0StandardTextToVideoArgs { + prompt: "a wave crashes against a rocky shoreline at sunset".to_string(), + generate_audio: Some(true), + negative_prompt: None, + duration: Some(EnqueueKling3p0StandardTextToVideoDuration::ThreeSeconds), + aspect_ratio: Some(ar), + api_key: &api_key, + webhook_url: "https://example.com/webhook", + }; + let result = enqueue_kling_3p0_standard_text_to_video_webhook(args).await?; + println!("result: {:?}", result); + } + + Ok(()) } - #[test] - fn test_cost_standard_audio_off_3s() { - let api_key = FalApiKey::from_str(""); - let args = EnqueueKling3p0StandardTextToVideoArgs { - prompt: String::new(), - generate_audio: Some(false), - negative_prompt: None, - duration: Some(EnqueueKling3p0StandardTextToVideoDuration::ThreeSeconds), - aspect_ratio: None, - webhook_url: "https://example.com", - api_key: &api_key, - }; - // $0.168 * 3 = $0.504 = ceil(50.4) = 51 cents - assert_eq!(args.calculate_cost_in_cents(), 51); - } + #[tokio::test] + #[ignore] // manually run — fires a real API request per variant (expensive) + async fn test_all_durations() -> AnyhowResult<()> { + let secret = read_to_string("/Users/bt/Artcraft/credentials/fal_api_key.txt")?; + let api_key = FalApiKey::from_str(&secret); - #[test] - fn test_cost_standard_audio_off_15s() { - let api_key = FalApiKey::from_str(""); - let args = EnqueueKling3p0StandardTextToVideoArgs { - prompt: String::new(), - generate_audio: Some(false), - negative_prompt: None, - duration: Some(EnqueueKling3p0StandardTextToVideoDuration::FifteenSeconds), - aspect_ratio: None, - webhook_url: "https://example.com", - api_key: &api_key, - }; - // $0.168 * 15 = $2.52 = 252 cents - assert_eq!(args.calculate_cost_in_cents(), 252); + for dur in EnqueueKling3p0StandardTextToVideoDuration::iter() { + println!("--- duration: {:?} ---", dur); + let args = EnqueueKling3p0StandardTextToVideoArgs { + prompt: "a candle flame flickers in a dark room".to_string(), + generate_audio: Some(false), + negative_prompt: None, + duration: Some(dur), + aspect_ratio: Some(EnqueueKling3p0StandardTextToVideoAspectRatio::SixteenByNine), + api_key: &api_key, + webhook_url: "https://example.com/webhook", + }; + let result = enqueue_kling_3p0_standard_text_to_video_webhook(args).await?; + println!("result: {:?}", result); + } + + Ok(()) } }