use bashkit::{Bash, FileSystem, InMemoryFs};
use std::sync::Arc;
#[tokio::test(flavor = "multi_thread")]
async fn thousand_parallel_sessions_do_real_work() {
const N: usize = 1000;
let fs: Arc<dyn FileSystem> = Arc::new(InMemoryFs::new());
let handles: Vec<_> = (0..N)
.map(|i| {
let fs = Arc::clone(&fs);
tokio::spawn(async move {
let script = format!(
r#"
for j in 1 2 3 4 5 6 7 8 9 10; do
echo "value=$((j * {i}))"
done > /tmp/session_{i}.txt
awk -F= '{{s+=$2}} END {{print s}}' /tmp/session_{i}.txt
"#
);
let mut bash = Bash::builder().fs(fs).build();
let result = bash.exec(&script).await.expect("session must succeed");
(i, result.exit_code, result.stdout.trim().to_string())
})
})
.collect();
let mut completed = 0;
for handle in handles {
let (i, exit_code, stdout) = handle.await.expect("task must not panic");
assert_eq!(exit_code, 0, "session {i} should exit 0");
assert_eq!(stdout, (55 * i).to_string(), "session {i} wrong sum");
completed += 1;
}
assert_eq!(completed, N, "all {N} sessions must complete");
}
#[tokio::test(flavor = "multi_thread")]
async fn parallel_sessions_shared_fs_no_cross_contamination() {
const N: usize = 500;
let fs: Arc<dyn FileSystem> = Arc::new(InMemoryFs::new());
let handles: Vec<_> = (0..N)
.map(|i| {
let fs = Arc::clone(&fs);
tokio::spawn(async move {
let script = format!("echo marker-{i} > /tmp/f_{i}.txt; cat /tmp/f_{i}.txt");
let mut bash = Bash::builder().fs(fs).build();
let out = bash.exec(&script).await.expect("session must succeed");
(i, out.stdout.trim().to_string())
})
})
.collect();
for handle in handles {
let (i, stdout) = handle.await.expect("task must not panic");
assert_eq!(stdout, format!("marker-{i}"), "session {i} saw wrong file");
}
}