sub-aligator/tests/concurrency.rs

72 lines
1.8 KiB
Rust

use sqlx::migrate::{MigrateDatabase, Migrator};
use sqlx::{sqlite::SqlitePoolOptions, Sqlite, SqlitePool};
use std::collections::HashSet;
use std::path::Path;
async fn setup_db() -> SqlitePool {
let url = "sqlite::memory:";
Sqlite::create_database(url).await.ok();
let pool = SqlitePoolOptions::new()
.max_connections(20)
.connect(url)
.await
.unwrap();
Migrator::new(Path::new("./migrations"))
.await
.unwrap()
.run(&pool)
.await
.unwrap();
sqlx::query(
"INSERT INTO pools (slug, name, cidr, kind, allowed_prefixes_json, enabled, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)"
)
.bind("vlan")
.bind("VLAN / zákaznické subnety")
.bind("10.91.0.0/16")
.bind("VLAN")
.bind("[20,21,22,23,24,25,26,27,28,29,30]")
.bind(1)
.bind(chrono::Utc::now().to_rfc3339())
.execute(&pool)
.await
.unwrap();
pool
}
#[tokio::test]
async fn concurrent_allocations_do_not_overlap() {
let pool = setup_db().await;
let mut handles = vec![];
for i in 0..5 {
let p = pool.clone();
handles.push(tokio::spawn(async move {
sub_aligator::handlers::allocations::allocate_in_tx(
&p,
1,
"10.91.0.0/16",
&[24],
24,
&format!("test allocation {}", i),
"",
"local",
)
.await
}));
}
let results: Vec<_> = futures::future::join_all(handles).await;
let mut cidrs = HashSet::new();
for r in results {
let Ok(Ok((allocation, _))) = r else { panic!("task failed") };
assert!(
cidrs.insert(allocation.cidr.clone()),
"duplicate CIDR allocated: {}",
allocation.cidr
);
}
assert_eq!(cidrs.len(), 5);
}