use super::*;
use crate::ffmpeg::FfmpegError;
use crate::fs::{FileStat, FsError};
use crate::http::{HttpRequest, TransportError};
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::task::{Context, Poll};
#[derive(Default)]
struct YieldOnce {
yielded: bool,
}
impl Future for YieldOnce {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
if self.yielded {
Poll::Ready(())
} else {
self.yielded = true;
cx.waker().wake_by_ref();
Poll::Pending
}
}
}
struct GatedHttp {
inner: ScriptedHttp,
inflight: Arc<AtomicUsize>,
peak: Arc<AtomicUsize>,
}
impl GatedHttp {
fn new(inner: ScriptedHttp) -> Self {
Self {
inner,
inflight: Arc::new(AtomicUsize::new(0)),
peak: Arc::new(AtomicUsize::new(0)),
}
}
fn peak(&self) -> usize {
self.peak.load(Ordering::SeqCst)
}
fn count(&self, needle: &str) -> usize {
self.inner.count(needle)
}
}
impl Http for GatedHttp {
async fn send(&self, request: HttpRequest) -> Result<HttpResponse, TransportError> {
let now = self.inflight.fetch_add(1, Ordering::SeqCst) + 1;
self.peak.fetch_max(now, Ordering::SeqCst);
YieldOnce::default().await;
let out = self.inner.send(request).await;
self.inflight.fetch_sub(1, Ordering::SeqCst);
out
}
}
fn download(id: &str, format: AudioFormat) -> (Clip, Desired, Action) {
let c = clip(id);
let d = desired(c.clone(), format);
let action = Action::Download {
clip: c.clone(),
lineage: LineageContext::own_root(&c),
path: d.path.clone(),
format,
};
(c, d, action)
}
fn opts_with(concurrency: u32) -> ExecOptions {
ExecOptions {
concurrency,
..small_poll()
}
}
#[test]
fn concurrency_never_exceeds_the_configured_bound() {
let count = 6;
let concurrency = 3;
let mut scripted = ScriptedHttp::new().with_auth();
let mut actions = Vec::new();
let mut desireds = Vec::new();
for i in 0..count {
let id = format!("c{i}");
scripted = scripted.route(&format!("{id}.mp3"), Reply::ok(b"mp3-body".to_vec()));
let (_c, d, action) = download(&id, AudioFormat::Mp3);
actions.push(action);
desireds.push(d);
}
let http = GatedHttp::new(scripted);
let fs = MemFs::new();
let plan = Plan { actions };
let mut manifest = Manifest::new();
let outcome = run_gated_fs(
&plan,
&mut manifest,
&desireds,
&http,
&fs,
&opts_with(concurrency),
);
assert_eq!(outcome.downloaded, count);
assert!(
http.peak() <= concurrency as usize,
"peak {} exceeded the bound {concurrency}",
http.peak()
);
assert_eq!(
http.peak(),
concurrency as usize,
"expected the run to saturate the bound"
);
}
fn run_gated_fs(
plan: &Plan,
manifest: &mut Manifest,
desired: &[Desired],
http: &GatedHttp,
fs: &MemFs,
opts: &ExecOptions,
) -> ExecOutcome {
let ffmpeg = StubFfmpeg::flac();
let clock = RecordingClock::new();
let mut albums = BTreeMap::new();
let mut playlists = BTreeMap::new();
let client = SunoClient::new(ClerkAuth::new("eyJtoken"), RecordingClock::new());
pollster::block_on(execute(
plan,
manifest,
&mut albums,
&mut playlists,
desired,
&HashMap::new(),
Ports {
client: &client,
http,
fs,
ffmpeg: &ffmpeg,
clock: &clock,
},
opts,
))
}
#[test]
fn a_failing_clip_does_not_abort_the_others() {
let mut scripted = ScriptedHttp::new().with_auth();
scripted = scripted
.route("ok1.mp3", Reply::ok(b"one".to_vec()))
.route("bad.mp3", Reply::status(404))
.route("ok2.mp3", Reply::ok(b"two".to_vec()));
let (_a, d1, a1) = download("ok1", AudioFormat::Mp3);
let (_b, d2, a2) = download("bad", AudioFormat::Mp3);
let (_c, d3, a3) = download("ok2", AudioFormat::Mp3);
let http = GatedHttp::new(scripted);
let fs = MemFs::new();
let plan = Plan {
actions: vec![a1, a2, a3],
};
let mut manifest = Manifest::new();
let outcome = run_gated_fs(
&plan,
&mut manifest,
&[d1, d2, d3],
&http,
&fs,
&opts_with(3),
);
assert_eq!(outcome.downloaded, 2);
assert_eq!(outcome.failed(), 1);
assert_eq!(outcome.status, RunStatus::Completed);
assert_eq!(outcome.failures[0].clip_id, "bad");
assert!(manifest.get("ok1").is_some());
assert!(manifest.get("ok2").is_some());
assert!(manifest.get("bad").is_none());
}
#[test]
fn outcome_is_identical_across_concurrency_levels() {
fn build() -> (Plan, Vec<Desired>) {
let mut actions = Vec::new();
let mut desireds = Vec::new();
for id in ["a", "b", "c", "d"] {
let (_c, d, action) = download(id, AudioFormat::Mp3);
actions.push(action);
desireds.push(d);
}
let (_e, de, ae) = download("fail", AudioFormat::Mp3);
actions.insert(2, ae);
desireds.push(de);
actions.push(Action::Skip {
clip_id: "gone".to_owned(),
});
actions.push(Action::Delete {
path: "old.mp3".to_owned(),
clip_id: "old".to_owned(),
});
(Plan { actions }, desireds)
}
fn http() -> ScriptedHttp {
ScriptedHttp::new()
.with_auth()
.route("a.mp3", Reply::ok(b"a".to_vec()))
.route("b.mp3", Reply::ok(b"b".to_vec()))
.route("c.mp3", Reply::ok(b"c".to_vec()))
.route("d.mp3", Reply::ok(b"d".to_vec()))
.route("fail.mp3", Reply::status(404))
}
fn seed_manifest() -> Manifest {
let mut m = Manifest::new();
m.insert("old".to_owned(), entry("old.mp3", AudioFormat::Mp3));
m
}
let (plan, desireds) = build();
let mut m1 = seed_manifest();
let fs1 = MemFs::new().with_file("old.mp3", b"x".to_vec());
let out1 = run_gated_fs(
&plan,
&mut m1,
&desireds,
&GatedHttp::new(http()),
&fs1,
&opts_with(1),
);
let mut m8 = seed_manifest();
let fs8 = MemFs::new().with_file("old.mp3", b"x".to_vec());
let out8 = run_gated_fs(
&plan,
&mut m8,
&desireds,
&GatedHttp::new(http()),
&fs8,
&opts_with(8),
);
assert_eq!(out1, out8, "outcome must not depend on concurrency");
assert_eq!(m1, m8, "final manifest must not depend on concurrency");
assert_eq!(out8.downloaded, 4);
assert_eq!(out8.deleted, 1);
assert_eq!(out8.skipped, 1);
assert_eq!(out8.failed(), 1);
}
#[test]
fn a_systemic_disk_full_aborts_promptly() {
let count = 8;
let concurrency = 2;
let mut scripted = ScriptedHttp::new().with_auth();
let mut actions = Vec::new();
let mut desireds = Vec::new();
for i in 0..count {
let id = format!("d{i}");
scripted = scripted.route(&format!("{id}.mp3"), Reply::ok(b"mp3-body".to_vec()));
let (_c, d, action) = download(&id, AudioFormat::Mp3);
actions.push(action);
desireds.push(d);
}
let fs = MemFs::new().fail_write_out_of_space("d0.mp3");
let http = GatedHttp::new(scripted);
let plan = Plan { actions };
let mut manifest = Manifest::new();
let outcome = run_gated_fs(
&plan,
&mut manifest,
&desireds,
&http,
&fs,
&opts_with(concurrency),
);
assert_eq!(outcome.status, RunStatus::DiskFull);
assert!(
outcome.downloaded < count,
"a systemic abort must stop remaining work, downloaded {}",
outcome.downloaded
);
}
#[test]
fn limiter_records_a_rate_limit_under_concurrent_calls() {
let scripted = ScriptedHttp::new()
.with_auth()
.route_seq(
"/gen/x/wav_file/",
vec![
Reply::status(429),
Reply::json(r#"{"wav_file_url": "https://cdn1.suno.ai/x.wav"}"#),
],
)
.route(
"/gen/y/wav_file/",
Reply::json(r#"{"wav_file_url": "https://cdn1.suno.ai/y.wav"}"#),
)
.route(
"/gen/z/wav_file/",
Reply::json(r#"{"wav_file_url": "https://cdn1.suno.ai/z.wav"}"#),
)
.route("x.wav", Reply::ok(b"wav-x".to_vec()))
.route("y.wav", Reply::ok(b"wav-y".to_vec()))
.route("z.wav", Reply::ok(b"wav-z".to_vec()));
let mut actions = Vec::new();
let mut desireds = Vec::new();
for id in ["x", "y", "z"] {
let (_c, d, action) = download(id, AudioFormat::Flac);
actions.push(action);
desireds.push(d);
}
let plan = Plan { actions };
let fs = MemFs::new();
let ffmpeg = StubFfmpeg::flac();
let clock = RecordingClock::new();
let mut albums = BTreeMap::new();
let mut playlists = BTreeMap::new();
let mut manifest = Manifest::new();
let client = SunoClient::new(ClerkAuth::new("eyJtoken"), RecordingClock::new());
let outcome = pollster::block_on(execute(
&plan,
&mut manifest,
&mut albums,
&mut playlists,
&desireds,
&HashMap::new(),
Ports {
client: &client,
http: &scripted,
fs: &fs,
ffmpeg: &ffmpeg,
clock: &clock,
},
&opts_with(3),
));
assert_eq!(outcome.downloaded, 3);
assert_eq!(outcome.failed(), 0);
assert!(
(client.limiter_rate() - 1.0).abs() < 1e-9,
"one 429 must halve the rate to 1.0, got {}",
client.limiter_rate()
);
}
#[test]
fn a_download_is_committed_in_plan_order_around_a_rename() {
let c_new = clip("new");
let mut d_new = desired(c_new.clone(), AudioFormat::Mp3);
d_new.path = "shared.mp3".to_owned();
let plan = Plan {
actions: vec![
Action::Rename {
from: "shared.mp3".to_owned(),
to: "moved.mp3".to_owned(),
},
Action::Download {
clip: c_new.clone(),
lineage: LineageContext::own_root(&c_new),
path: "shared.mp3".to_owned(),
format: AudioFormat::Mp3,
},
],
};
let scripted = ScriptedHttp::new()
.with_auth()
.route("new.mp3", Reply::ok(b"NEW-BODY".to_vec()));
let http = GatedHttp::new(scripted);
let fs = MemFs::new().with_file("shared.mp3", b"ORIGINAL".to_vec());
let mut manifest = Manifest::new();
manifest.insert("orig", entry("shared.mp3", AudioFormat::Mp3));
let outcome = run_gated_fs(&plan, &mut manifest, &[d_new], &http, &fs, &opts_with(4));
assert_eq!(outcome.renamed, 1);
assert_eq!(outcome.downloaded, 1);
assert_eq!(
fs.read_file("moved.mp3").as_deref(),
Some(&b"ORIGINAL"[..]),
"the rename must carry the original bytes, untouched by the download"
);
let landed = fs.read_file("shared.mp3").expect("new download must land");
assert_ne!(
landed, b"ORIGINAL",
"the new download must replace the moved original, not corrupt it"
);
assert_eq!(manifest.get("orig").unwrap().path, "moved.mp3");
assert_eq!(manifest.get("new").unwrap().path, "shared.mp3");
}
#[test]
fn an_aborted_reformat_leaves_the_old_file_and_manifest_consistent() {
let boom = clip("boom");
let mut d_boom = desired(boom.clone(), AudioFormat::Mp3);
d_boom.path = "boom.mp3".to_owned();
let reformer = clip("r");
let d_reformer = desired(reformer.clone(), AudioFormat::Mp3);
let plan = Plan {
actions: vec![
Action::Download {
clip: boom.clone(),
lineage: LineageContext::own_root(&boom),
path: "boom.mp3".to_owned(),
format: AudioFormat::Mp3,
},
Action::Reformat {
clip: reformer.clone(),
path: "r_new.mp3".to_owned(),
from_path: "r_old.flac".to_owned(),
from: AudioFormat::Flac,
to: AudioFormat::Mp3,
},
],
};
let scripted = ScriptedHttp::new()
.with_auth()
.route("boom.mp3", Reply::ok(b"boom-body".to_vec()))
.route("r.mp3", Reply::ok(b"reformatted".to_vec()));
let http = GatedHttp::new(scripted);
let fs = MemFs::new()
.with_file("r_old.flac", b"OLD-FLAC".to_vec())
.fail_write_out_of_space("boom.mp3");
let mut manifest = Manifest::new();
manifest.insert("r", entry("r_old.flac", AudioFormat::Flac));
let outcome = run_gated_fs(
&plan,
&mut manifest,
&[d_boom, d_reformer],
&http,
&fs,
&opts_with(4),
);
assert_eq!(outcome.status, RunStatus::DiskFull);
assert!(
fs.exists("r_old.flac"),
"the old file must survive the abort"
);
assert!(
!fs.exists("r_new.mp3"),
"no reformatted file may be written"
);
let still = manifest.get("r").expect("the manifest must still track r");
assert_eq!(
still.path, "r_old.flac",
"the manifest must still point at the surviving old file"
);
assert_eq!(still.format, AudioFormat::Flac);
}
#[test]
fn a_systemic_abort_leaves_no_untracked_destination_files() {
let mut scripted = ScriptedHttp::new().with_auth();
let mut actions = Vec::new();
let mut desireds = Vec::new();
for id in ["a0", "a1", "boom", "a3", "a4"] {
scripted = scripted.route(&format!("{id}.mp3"), Reply::ok(b"body".to_vec()));
let (_c, d, action) = download(id, AudioFormat::Mp3);
actions.push(action);
desireds.push(d);
}
let http = GatedHttp::new(scripted);
let fs = MemFs::new().fail_write_out_of_space("boom.mp3");
let plan = Plan { actions };
let mut manifest = Manifest::new();
let outcome = run_gated_fs(&plan, &mut manifest, &desireds, &http, &fs, &opts_with(2));
assert_eq!(outcome.status, RunStatus::DiskFull);
let tracked: std::collections::BTreeSet<String> = manifest
.entries
.values()
.map(|entry| entry.path.clone())
.collect();
for path in fs.paths() {
assert!(
tracked.contains(&path),
"found an untracked destination file: {path}"
);
}
assert!(
!fs.exists("a3.mp3"),
"uncommitted renders must not be on disk"
);
assert!(
!fs.exists("a4.mp3"),
"uncommitted renders must not be on disk"
);
}
struct CountingFfmpeg {
inner: StubFfmpeg,
held: Arc<AtomicUsize>,
peak: Arc<AtomicUsize>,
}
impl Ffmpeg for CountingFfmpeg {
fn wav_to_lossless(
&self,
wav: &[u8],
format: AudioFormat,
) -> impl Future<Output = Result<Vec<u8>, FfmpegError>> + Send {
let fut = self.inner.wav_to_lossless(wav, format);
let held = self.held.clone();
let peak = self.peak.clone();
async move {
let out = fut.await;
if out.is_ok() {
let now = held.fetch_add(1, Ordering::SeqCst) + 1;
peak.fetch_max(now, Ordering::SeqCst);
}
out
}
}
fn mp4_to_webp(
&self,
mp4: &[u8],
settings: WebpEncodeSettings,
) -> impl Future<Output = Result<Vec<u8>, FfmpegError>> + Send {
self.inner.mp4_to_webp(mp4, settings)
}
}
struct CountingFs {
inner: MemFs,
held: Arc<AtomicUsize>,
}
impl Filesystem for CountingFs {
fn write_atomic(&self, path: &str, bytes: &[u8]) -> Result<(), FsError> {
let out = self.inner.write_atomic(path, bytes);
self.held.fetch_sub(1, Ordering::SeqCst);
out
}
fn rename(&self, from: &str, to: &str) -> Result<(), FsError> {
self.inner.rename(from, to)
}
fn remove(&self, path: &str) -> Result<(), FsError> {
self.inner.remove(path)
}
fn prune_empty_dirs(&self, root: &str) -> Result<(), FsError> {
self.inner.prune_empty_dirs(root)
}
fn read(&self, path: &str) -> Result<Vec<u8>, FsError> {
self.inner.read(path)
}
fn metadata(&self, path: &str) -> Option<FileStat> {
self.inner.metadata(path)
}
}
#[test]
fn rendered_payloads_in_memory_stay_bounded_by_concurrency() {
let count = 12;
let concurrency = 3;
let mut scripted = ScriptedHttp::new().with_auth();
let mut actions = Vec::new();
let mut desireds = Vec::new();
for i in 0..count {
let id = format!("f{i}");
scripted = scripted
.route(
&format!("/gen/{id}/wav_file/"),
Reply::json(&format!(
r#"{{"wav_file_url": "https://cdn1.suno.ai/{id}.wav"}}"#
)),
)
.route(&format!("{id}.wav"), Reply::ok(b"wav-body".to_vec()));
let (_c, d, action) = download(&id, AudioFormat::Flac);
actions.push(action);
desireds.push(d);
}
let http = GatedHttp::new(scripted);
let held = Arc::new(AtomicUsize::new(0));
let peak = Arc::new(AtomicUsize::new(0));
let ffmpeg = CountingFfmpeg {
inner: StubFfmpeg::flac(),
held: held.clone(),
peak: peak.clone(),
};
let fs = CountingFs {
inner: MemFs::new(),
held: held.clone(),
};
let clock = RecordingClock::new();
let mut albums = BTreeMap::new();
let mut playlists = BTreeMap::new();
let mut manifest = Manifest::new();
let client = SunoClient::new(ClerkAuth::new("eyJtoken"), RecordingClock::new());
let plan = Plan { actions };
let outcome = pollster::block_on(execute(
&plan,
&mut manifest,
&mut albums,
&mut playlists,
&desireds,
&HashMap::new(),
Ports {
client: &client,
http: &http,
fs: &fs,
ffmpeg: &ffmpeg,
clock: &clock,
},
&opts_with(concurrency),
));
assert_eq!(outcome.downloaded, count as usize);
assert_eq!(
held.load(Ordering::SeqCst),
0,
"every payload must be committed"
);
assert!(
peak.load(Ordering::SeqCst) <= concurrency as usize + 1,
"peak live payloads {} exceeded the bound {}",
peak.load(Ordering::SeqCst),
concurrency + 1
);
assert!(
peak.load(Ordering::SeqCst) >= 2,
"the render should genuinely overlap, peak was {}",
peak.load(Ordering::SeqCst)
);
}
#[test]
fn artifact_fetches_run_concurrently() {
let count = 4usize;
let concurrency = 2u32;
let mut scripted = ScriptedHttp::new().with_auth();
let mut actions = Vec::new();
let mut manifest = Manifest::new();
for i in 0..count {
let id = format!("a{i}");
scripted = scripted.route(&format!("{id}.jpg"), Reply::ok(b"jpg-bytes".to_vec()));
manifest.insert(&id, entry(&format!("{id}.mp3"), AudioFormat::Mp3));
actions.push(Action::WriteArtifact {
kind: ArtifactKind::CoverJpg,
path: format!("{id}/cover.jpg"),
source_url: format!("https://art.suno.ai/{id}.jpg"),
hash: format!("h{i}"),
owner_id: id,
content: None,
});
}
let http = GatedHttp::new(scripted);
let fs = MemFs::new();
let plan = Plan { actions };
let outcome = run_gated_fs(
&plan,
&mut manifest,
&[],
&http,
&fs,
&opts_with(concurrency),
);
assert_eq!(outcome.artifacts_written, count);
assert_eq!(outcome.failed(), 0);
assert!(
http.peak() >= concurrency as usize,
"artifact fetches must overlap: peak {} < concurrency {}",
http.peak(),
concurrency,
);
}
#[test]
fn stem_fetches_run_concurrently() {
let count = 4usize;
let concurrency = 2u32;
let mut scripted = ScriptedHttp::new().with_auth();
let mut actions = Vec::new();
let mut manifest = Manifest::new();
for i in 0..count {
let id = format!("s{i}");
scripted = scripted.route(&format!("{id}voc.mp3"), Reply::ok(b"stem-bytes".to_vec()));
manifest.insert(&id, entry(&format!("{id}.mp3"), AudioFormat::Mp3));
actions.push(Action::WriteStem {
clip_id: id.clone(),
key: "voc".to_owned(),
stem_id: format!("{id}voc"),
path: format!("{id}.stems/voc.mp3"),
source_url: format!("https://cdn1.suno.ai/{id}voc.mp3"),
format: StemFormat::Mp3,
hash: format!("h{i}"),
});
}
let http = GatedHttp::new(scripted);
let fs = MemFs::new();
let plan = Plan { actions };
let outcome = run_gated_fs(
&plan,
&mut manifest,
&[],
&http,
&fs,
&opts_with(concurrency),
);
assert_eq!(outcome.artifacts_written, count);
assert_eq!(outcome.failed(), 0);
assert!(
http.peak() >= concurrency as usize,
"stem fetches must overlap: peak {} < concurrency {}",
http.peak(),
concurrency,
);
}
#[test]
fn prepareable_outcome_is_identical_across_concurrency_levels_with_artifacts_and_stems() {
fn build() -> (Plan, Vec<Desired>) {
let mut actions = Vec::new();
let mut desireds = Vec::new();
for id in ["x", "y", "z"] {
let (_c, d, action) = download(id, AudioFormat::Mp3);
desireds.push(d);
actions.push(action);
actions.push(Action::WriteArtifact {
kind: ArtifactKind::CoverJpg,
path: format!("{id}/cover.jpg"),
source_url: format!("https://art.suno.ai/{id}.jpg"),
hash: format!("art-{id}"),
owner_id: id.to_owned(),
content: None,
});
actions.push(Action::WriteStem {
clip_id: id.to_owned(),
key: "voc".to_owned(),
stem_id: format!("{id}voc"),
path: format!("{id}.stems/voc.mp3"),
source_url: format!("https://cdn1.suno.ai/{id}voc.mp3"),
format: StemFormat::Mp3,
hash: format!("stem-{id}"),
});
}
let (_f, df, af) = download("fail", AudioFormat::Mp3);
desireds.push(df);
actions.insert(3, af);
actions.push(Action::Delete {
path: "old.mp3".to_owned(),
clip_id: "old".to_owned(),
});
(Plan { actions }, desireds)
}
fn http() -> ScriptedHttp {
ScriptedHttp::new()
.with_auth()
.route("x.mp3", Reply::ok(b"x-audio".to_vec()))
.route("y.mp3", Reply::ok(b"y-audio".to_vec()))
.route("z.mp3", Reply::ok(b"z-audio".to_vec()))
.route("fail.mp3", Reply::status(404))
.route("x.jpg", Reply::ok(b"x-jpg".to_vec()))
.route("y.jpg", Reply::ok(b"y-jpg".to_vec()))
.route("z.jpg", Reply::ok(b"z-jpg".to_vec()))
.route("xvoc.mp3", Reply::ok(b"x-voc".to_vec()))
.route("yvoc.mp3", Reply::ok(b"y-voc".to_vec()))
.route("zvoc.mp3", Reply::ok(b"z-voc".to_vec()))
}
fn seed_manifest() -> Manifest {
let mut m = Manifest::new();
m.insert("old".to_owned(), entry("old.mp3", AudioFormat::Mp3));
m
}
let (plan, desireds) = build();
let mut m1 = seed_manifest();
let fs1 = MemFs::new().with_file("old.mp3", b"x".to_vec());
let out1 = run_gated_fs(
&plan,
&mut m1,
&desireds,
&GatedHttp::new(http()),
&fs1,
&opts_with(1),
);
let mut m8 = seed_manifest();
let fs8 = MemFs::new().with_file("old.mp3", b"x".to_vec());
let out8 = run_gated_fs(
&plan,
&mut m8,
&desireds,
&GatedHttp::new(http()),
&fs8,
&opts_with(8),
);
assert_eq!(out1, out8, "outcome must not depend on concurrency");
assert_eq!(m1, m8, "final manifest must not depend on concurrency");
assert_eq!(out8.downloaded, 3);
assert_eq!(out8.deleted, 1);
assert_eq!(out8.failed(), 1);
assert_eq!(out8.artifacts_written, 6);
}
#[test]
fn both_folder_covers_fetch_video_cover_once_under_concurrency() {
let scripted = ScriptedHttp::new()
.with_auth()
.route("root/video.mp4", Reply::ok(b"mp4-bytes".to_vec()))
.route("d0.mp3", Reply::ok(b"audio".to_vec()))
.route("d1.mp3", Reply::ok(b"audio".to_vec()));
let mut actions = vec![
Action::WriteArtifact {
kind: ArtifactKind::FolderWebp,
path: "album/cover.webp".to_owned(),
source_url: "https://cdn.suno.ai/root/video.mp4".to_owned(),
hash: "wh".to_owned(),
owner_id: "root".to_owned(),
content: None,
},
Action::WriteArtifact {
kind: ArtifactKind::FolderMp4,
path: "album/cover.mp4".to_owned(),
source_url: "https://cdn.suno.ai/root/video.mp4".to_owned(),
hash: "mh".to_owned(),
owner_id: "root".to_owned(),
content: None,
},
];
let mut desireds = vec![];
for id in ["d0", "d1"] {
let (_c, d, a) = download(id, AudioFormat::Mp3);
actions.push(a);
desireds.push(d);
}
let plan = Plan { actions };
let http = GatedHttp::new(scripted);
let ffmpeg = StubFfmpeg::webp();
let clock = RecordingClock::new();
let mut manifest = Manifest::new();
let mut albums = BTreeMap::new();
let mut playlists = BTreeMap::new();
let client = SunoClient::new(ClerkAuth::new("eyJtoken"), RecordingClock::new());
pollster::block_on(execute(
&plan,
&mut manifest,
&mut albums,
&mut playlists,
&desireds,
&HashMap::new(),
Ports {
client: &client,
http: &http,
fs: &MemFs::new(),
ffmpeg: &ffmpeg,
clock: &clock,
},
&opts_with(4),
));
assert_eq!(
http.count("root/video.mp4"),
1,
"video_cover_url must be fetched exactly once even under concurrency"
);
}
#[test]
fn existing_clip_audio_and_cover_sidecar_share_cover_fetch() {
let c = art_clip("e");
let cover_url = c.image_large_url.clone();
let d = desired(c.clone(), AudioFormat::Mp3);
let scripted = ScriptedHttp::new()
.with_auth()
.route("e.mp3", Reply::ok(b"audio".to_vec()))
.route("e/large.jpg", Reply::ok(b"cover-jpg".to_vec()));
let plan = Plan {
actions: vec![
Action::Reformat {
clip: c,
path: "e.mp3".to_owned(),
from_path: "e-old.mp3".to_owned(),
from: AudioFormat::Mp3,
to: AudioFormat::Mp3,
},
Action::WriteArtifact {
kind: ArtifactKind::CoverJpg,
path: "e/cover.jpg".to_owned(),
source_url: cover_url,
hash: "new-art".to_owned(),
owner_id: "e".to_owned(),
content: None,
},
],
};
let mut manifest = Manifest::new();
manifest.insert("e".to_owned(), entry("e-old.mp3", AudioFormat::Mp3));
let fs = MemFs::new().with_file("e-old.mp3", b"old-audio".to_vec());
let http = GatedHttp::new(scripted);
let outcome = run_gated_fs(&plan, &mut manifest, &[d], &http, &fs, &opts_with(4));
assert_eq!(outcome.reformatted, 1);
assert_eq!(outcome.failed(), 0);
assert_eq!(
http.count("e/large.jpg"),
1,
"cover must be fetched exactly once, not once per concurrent action"
);
}