use faucet_conformance::assert_config_schema_valid_value;
use faucet_source_mysql::{MysqlSource, MysqlSourceConfig};
use std::sync::OnceLock;
use testcontainers::{ContainerAsync, runners::AsyncRunner};
use testcontainers_modules::mysql::Mysql;
use tokio::sync::Semaphore;
#[test]
fn conformance_config_schema_valid() {
let schema = serde_json::to_value(schemars::schema_for!(MysqlSourceConfig)).unwrap();
assert_config_schema_valid_value(&schema, "faucet-source-mysql");
}
fn startup_limit() -> &'static Semaphore {
static SEM: OnceLock<Semaphore> = OnceLock::new();
SEM.get_or_init(|| Semaphore::new(2))
}
async fn start_mysql() -> (ContainerAsync<Mysql>, String) {
let _permit = startup_limit()
.acquire()
.await
.expect("startup semaphore closed");
let image = Mysql::default();
let container: ContainerAsync<Mysql> = image.start().await.expect("mysql container start");
let port = container
.get_host_port_ipv4(3306)
.await
.expect("mysql port");
let url = format!("mysql://root@127.0.0.1:{port}/test");
(container, url)
}
async fn seed_events(url: &str, n: i64) {
use sqlx::Connection;
let mut conn = sqlx::MySqlConnection::connect(url)
.await
.expect("connect for seed");
sqlx::query("CREATE TABLE events (id BIGINT PRIMARY KEY)")
.execute(&mut conn)
.await
.expect("create table");
sqlx::query("SET SESSION cte_max_recursion_depth = 1000000")
.execute(&mut conn)
.await
.expect("set cte depth");
sqlx::query(
"INSERT INTO events (id) \
WITH RECURSIVE seq(n) AS (SELECT 1 UNION ALL SELECT n + 1 FROM seq WHERE n < ?) \
SELECT n FROM seq",
)
.bind(n)
.execute(&mut conn)
.await
.expect("insert rows");
conn.close().await.expect("close conn");
}
#[tokio::test(flavor = "multi_thread")]
async fn conformance_bounded_memory() {
let (_container, url) = start_mysql().await;
seed_events(&url, 5_000).await;
let config =
MysqlSourceConfig::new(url, "SELECT id FROM events ORDER BY id").with_batch_size(250);
let source = MysqlSource::new(config).await.expect("source new");
faucet_conformance::assert_bounded_memory(&source, 250, 5_000).await;
}
#[tokio::test(flavor = "multi_thread")]
async fn conformance_errors_not_panics() {
let (_container, url) = start_mysql().await;
let config = MysqlSourceConfig::new(url, "SELECT id FROM missing_table");
let source = MysqlSource::new(config)
.await
.expect("builds; query fails at read");
faucet_conformance::assert_errors_not_panics(&source).await;
}