testcontainers_modules/rqlite/
mod.rs

1use testcontainers::{
2    core::{wait::HttpWaitStrategy, ContainerPort, WaitFor},
3    Image,
4};
5
6/// Port that the [`RQLite`] container has internally
7/// Can be rebound externally via [`testcontainers::core::ImageExt::with_mapped_port`]
8///
9/// [`RQLite`]: https://rqlite.io/
10pub const RQLITE_PORT: ContainerPort = ContainerPort::Tcp(4001);
11
12const NAME: &str = "rqlite/rqlite";
13const TAG: &str = "8.36.3";
14
15/// Module to work with [`RQLite`] inside of tests.
16///
17/// This module is based on the official [`RQLite docker image`].
18///
19/// # Example
20/// ```
21/// use testcontainers_modules::{rqlite, testcontainers::runners::SyncRunner};
22///
23/// let rqlite = rqlite::RQLite::default().start().unwrap();
24/// let http_port = rqlite.get_host_port_ipv4(4001).unwrap();
25///
26/// // do something with the started rqlite instance..
27/// ```
28///
29/// [`RQLite`]: https://rqlite.io/
30/// [`RQLite docker image`]: https://hub.docker.com/r/rqlite/rqlite/
31#[derive(Debug, Default, Clone)]
32pub struct RQLite {
33    /// (remove if there is another variable)
34    /// Field is included to prevent this struct to be a unit struct.
35    /// This allows extending functionality (and thus further variables) without breaking changes
36    _priv: (),
37}
38
39impl Image for RQLite {
40    fn name(&self) -> &str {
41        NAME
42    }
43
44    fn tag(&self) -> &str {
45        TAG
46    }
47
48    fn ready_conditions(&self) -> Vec<WaitFor> {
49        vec![
50            WaitFor::http(HttpWaitStrategy::new("/status").with_expected_status_code(200_u16)),
51            WaitFor::message_on_stderr("is now Leader"),
52        ]
53    }
54
55    fn expose_ports(&self) -> &[ContainerPort] {
56        &[RQLITE_PORT]
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use testcontainers::runners::AsyncRunner;
63
64    use crate::rqlite::RQLite;
65
66    #[tokio::test]
67    async fn rqlite_db() -> Result<(), Box<dyn std::error::Error + 'static>> {
68        let _ = pretty_env_logger::try_init();
69        let node = RQLite::default().start().await?;
70        let host_ip = node.get_host().await?;
71        let host_port = node.get_host_port_ipv4(4001).await?;
72
73        let client = rqlite_rs::RqliteClientBuilder::new()
74            .known_host(format!("{host_ip}:{host_port}"))
75            .build()?;
76
77        let query = rqlite_rs::query!("SELECT 1+1")?;
78        let rows = client.fetch(query).await?;
79        assert_eq!(rows.len(), 1);
80
81        let first_row = &rows[0];
82        let first_column: i32 = first_row.get("1+1")?;
83        assert_eq!(first_column, 2);
84
85        Ok(())
86    }
87}