test omni api urls

This commit is contained in:
Hanashi
2026-08-09 23:48:22 -04:00
parent ba9f2b67b6
commit d76c474427
2 changed files with 97 additions and 7 deletions
@@ -12,7 +12,8 @@ use enums::common::generation::common_video_model::CommonVideoModel;
use artcraft_api_keys::ArtcraftApiKey;
use crate::http_server::endpoints::omni_gen::generate::video::tests::support::{
base_generate_request, ExpectedCredits, Seconds, TestHarness, STARTING_CREDITS,
base_generate_request, to_omni_api_request, ExpectedCredits, Seconds, TestHarness,
STARTING_CREDITS,
};
mod billing_parity {
@@ -45,6 +46,72 @@ mod billing_parity {
}
}
mod url_ingestion {
use super::*;
/// The omni_api-only URL-input flow, end to end: a stub-hosted video URL
/// is ingested (download → bucket upload → media_files row owned by the
/// API user), then billed exactly like the same request made with a media
/// TOKEN through omni_gen. Seedance 2.0 at 720p 5s with one reference
/// video: 111 credits on both paths, fully successful, no refund.
#[tokio::test]
#[cfg_attr(feature = "skip_database_tests", ignore)]
async fn reference_video_url_bills_like_a_media_token() {
const EXPECTED_CREDITS: u64 = 111;
let harness = TestHarness::create().await;
// omni_gen with a probeable media TOKEN pointing at the 5s stub fixture.
let web_user = harness.create_funded_user(STARTING_CREDITS).await;
let video_token = mysql_testing::fixtures::media_files::create_probeable_test_video_media_file(
&harness.pool,
&web_user.user_token,
5_000,
)
.await
.expect("probeable video fixture");
let mut request = base_generate_request(CommonVideoModel::Seedance2p0);
request.resolution = Some(CommonResolution::SevenTwentyP);
request.duration_seconds = Some(5);
request.reference_video_media_tokens = Some(vec![video_token]);
let response = harness
.post_generate(&web_user, request)
.await
.expect("omni_gen generation with reference token");
assert!(response.success);
// omni_api with a URL to the same 5s fixture, no token.
let api_user = harness.create_funded_user(STARTING_CREDITS).await;
let api_key = harness.create_api_key(&api_user).await;
let mut base = base_generate_request(CommonVideoModel::Seedance2p0);
base.resolution = Some(CommonResolution::SevenTwentyP);
base.duration_seconds = Some(5);
let mut api_request = to_omni_api_request(base);
api_request.reference_video_urls =
Some(vec![format!("{}/media/dur5000ms/source.mp4", harness.stub_kinovi_base_url)]);
let response = harness
.post_omni_api_request(&api_key, api_request)
.await
.expect("omni_api generation with reference URL");
assert!(response.success);
let web_debit = STARTING_CREDITS - harness.wallet_balance(&web_user).await;
let api_debit = STARTING_CREDITS - harness.wallet_balance(&api_user).await;
assert_eq!(web_debit, EXPECTED_CREDITS, "omni_gen token reference debited the wrong amount");
assert_eq!(api_debit, EXPECTED_CREDITS, "omni_api URL reference debited the wrong amount");
let entries = harness.ledger_entries(&api_user).await;
let debit = entries
.iter()
.find(|entry| entry.credits_delta < 0)
.expect("omni_api URL generation must have a debit ledger entry");
assert!(!debit.is_refunded, "successful URL-input generation must not be refunded");
}
}
mod api_key_only_auth {
use super::*;
@@ -180,6 +180,16 @@ impl TestHarness {
&self,
api_key: &ArtcraftApiKey,
request: OmniGenVideoCostAndGenerateRequest,
) -> Result<OmniGenVideoGenerateResponse, CommonWebError> {
self.post_omni_api_request(api_key, to_omni_api_request(request)).await
}
/// POST a raw omni_api request — URL input fields allowed — with API-key
/// authentication. Use this to exercise the URL-ingestion path.
pub async fn post_omni_api_request(
&self,
api_key: &ArtcraftApiKey,
api_request: OmniApiVideoGenerateRequest,
) -> Result<OmniGenVideoGenerateResponse, CommonWebError> {
let http_request = TestRequest::post()
.uri("/v1/omni_api/generate/video")
@@ -187,8 +197,6 @@ impl TestHarness {
.peer_addr("127.0.0.1:9999".parse().expect("peer addr"))
.to_http_request();
let api_request = to_omni_api_request(request);
omni_api_video_generate_handler(
http_request,
Json(api_request),
@@ -325,8 +333,12 @@ fn process_stub_kinovi_base_url() -> &'static String {
/// - `GET` paths containing `dur{millis}ms` serve a REAL generated video of
/// that duration (ffmpeg, cached per duration) — the reference-video
/// billing probe downloads and ffprobes these.
/// - `GET` paths under the `video_` bucket prefix (URL-ingested uploads)
/// serve a default 5s fixture video; other GETs are 404 so the
/// unreachable-token fixtures keep failing as intended.
/// - `POST …uploads.signedUploadUrl` answers with an upload URL back at this
/// stub; the subsequent `PUT` is accepted with 200.
/// stub; any `PUT` (that upload, or an S3 PutObject from the test bucket
/// client) is accepted with 200.
/// - Any other `POST` answers as a successful workflow.runTask with
/// process-unique order ids.
fn spawn_stub_server() -> String {
@@ -374,6 +386,13 @@ fn spawn_stub_server() -> String {
if request_line.starts_with("GET") {
match extract_fixture_duration_millis(&request_line) {
Some(millis) => ("200 OK", "video/mp4", fixture_video_bytes(millis)),
// URL-ingested uploads land under the `video_` bucket prefix
// (see MediaUploadKind::bucket_prefix); serve those a default
// 5s fixture. Token-fixture paths without a prefix stay 404 —
// the charge-then-refund tests depend on that.
None if request_line.contains("/video_") => {
("200 OK", "video/mp4", fixture_video_bytes(5_000))
}
None => ("404 Not Found", "text/plain", b"not found".to_vec()),
}
} else if request_line.starts_with("PUT") {
@@ -497,13 +516,16 @@ fn build_test_server_state(pool: MySqlPool, media_cdn_override_url: String) -> S
use std::sync::OnceLock;
static DUMMIES: OnceLock<ExpensiveDummies> = OnceLock::new();
let dummies = DUMMIES.get_or_init(|| retry_keychain_flake(|| {
// Bucket uploads (e.g. URL-input ingestion) PUT to the stub, which
// accepts anything; downloads then come back through the media CDN
// override, also the stub.
let dummy_bucket = || {
LegacyBucketClient::create(
"test-access-key",
"test-secret-key",
"auto",
"test-bucket",
"http://127.0.0.1:1",
&media_cdn_override_url,
None,
Some(Duration::from_secs(5)),
)
@@ -860,8 +882,9 @@ pub async fn assert_real_input_videos_charge(
}
/// Map an omni_gen request onto the omni_api request shape (token fields
/// only; the URL fields stay None — URL ingestion is not exercised here).
fn to_omni_api_request(request: OmniGenVideoCostAndGenerateRequest) -> OmniApiVideoGenerateRequest {
/// only; the URL fields start None — tests exercising URL ingestion set
/// them afterwards).
pub fn to_omni_api_request(request: OmniGenVideoCostAndGenerateRequest) -> OmniApiVideoGenerateRequest {
OmniApiVideoGenerateRequest {
idempotency_token: request.idempotency_token,
model: request.model,