diff --git a/Cargo.toml b/Cargo.toml index 7e8c891..ab8b052 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ watchdog = ["testcontainers/watchdog"] json = ["serde", "serde_json"] anvil = [] arrow_flightsql = [] +cassandra = [] clickhouse = ["http_wait"] cratedb = [] cncf_distribution = [] diff --git a/src/cassandra/mod.rs b/src/cassandra/mod.rs new file mode 100644 index 0000000..6b708a3 --- /dev/null +++ b/src/cassandra/mod.rs @@ -0,0 +1,85 @@ +use testcontainers::{core::WaitFor, Image}; + +const NAME: &str = "cassandra"; +const TAG: &str = "5.0.6"; + +/// Module to work with [`Cassandra`] inside of tests. +/// +/// This module is based on the official [`Cassandra docker image`]. +/// +/// # Example +/// ``` +/// use scylla::client::{session::Session, session_builder::SessionBuilder}; +/// use std::time::Duration; +/// use testcontainers::{runners::AsyncRunner, ImageExt}; +/// +/// #[tokio::test] +/// async fn default_cassandra() -> Result<(), Box> { +/// let image = ScyllaDB::default(); +/// let instance = image.start().await?; +/// let host = instance.get_host().await?; +/// let port = instance.get_host_port_ipv4(9042).await?; +/// let hostname = format!("{host}:{port}"); +/// let session: Session = SessionBuilder::new().known_node(hostname).build().await?; +/// +/// let prepared_statement = session +/// .prepare("SELECT release_version FROM system.local") +/// .await?; +/// let rows = session +/// .execute_unpaged(&prepared_statement, &[]) +/// .await? +/// .into_rows_result()?; +/// let (version,) = rows.single_row::<(String,)>()?; +/// assert_eq!(version, "5.0.6"); +/// Ok(()) +/// } +/// ``` +/// +/// [`Cassandra`]: https://cassandra.apache.org +/// [`Cassandra docker image`]: https://hub.docker.com/_/cassandra +#[derive(Default, Clone, Debug)] +pub struct Cassandra {} + +impl Image for Cassandra { + fn name(&self) -> &str { + NAME + } + + fn tag(&self) -> &str { + TAG + } + + fn ready_conditions(&self) -> Vec { + vec![WaitFor::message_on_either_std("Startup complete")] + } +} + +#[cfg(test)] +mod tests { + use scylla::client::{session::Session, session_builder::SessionBuilder}; + use std::time::Duration; + use testcontainers::{runners::AsyncRunner, ImageExt}; + + use super::*; + + #[tokio::test] + async fn cassandra_select_version() -> Result<(), Box> { + let image = Cassandra::default().with_startup_timeout(Duration::from_secs(240)); + let instance = image.start().await?; + let host = instance.get_host().await?; + let port = instance.get_host_port_ipv4(9042).await?; + let hostname = format!("{host}:{port}"); + let session: Session = SessionBuilder::new().known_node(hostname).build().await?; + + let prepared_statement = session + .prepare("SELECT release_version FROM system.local") + .await?; + let rows = session + .execute_unpaged(&prepared_statement, &[]) + .await? + .into_rows_result()?; + let (version,) = rows.single_row::<(String,)>()?; + assert_eq!(version, "5.0.6"); + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 8751541..4046b21 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,10 @@ pub mod arrow_flightsql; #[cfg_attr(docsrs, doc(cfg(feature = "azurite")))] /// **Azurite** (azure storage emulator) testcontainer pub mod azurite; +#[cfg(feature = "cassandra")] +#[cfg_attr(docsrs, doc(cfg(feature = "cassandra")))] +/// **Cassandra** (distributed NoSQL wide-column data store) testcontainer +pub mod cassandra; #[cfg(feature = "clickhouse")] #[cfg_attr(docsrs, doc(cfg(feature = "clickhouse")))] /// **Clickhouse** (analytics database) testcontainer