testcontainers_modules/clickhouse/
mod.rs1use std::{borrow::Cow, collections::BTreeMap};
2
3use testcontainers::{
4 core::{wait::HttpWaitStrategy, ContainerPort, WaitFor},
5 Image,
6};
7
8const DEFAULT_IMAGE_NAME: &str = "clickhouse/clickhouse-server";
9const DEFAULT_IMAGE_TAG: &str = "23.3.8.21-alpine";
10
11pub const CLICKHOUSE_PORT: ContainerPort = ContainerPort::Tcp(8123);
16
17#[derive(Debug, Default, Clone)]
34pub struct ClickHouse {
35 env_vars: BTreeMap<String, String>,
36}
37
38impl Image for ClickHouse {
39 fn name(&self) -> &str {
40 DEFAULT_IMAGE_NAME
41 }
42
43 fn tag(&self) -> &str {
44 DEFAULT_IMAGE_TAG
45 }
46
47 fn ready_conditions(&self) -> Vec<WaitFor> {
48 vec![WaitFor::http(
49 HttpWaitStrategy::new("/").with_expected_status_code(200_u16),
50 )]
51 }
52
53 fn env_vars(
54 &self,
55 ) -> impl IntoIterator<Item = (impl Into<Cow<'_, str>>, impl Into<Cow<'_, str>>)> {
56 &self.env_vars
57 }
58
59 fn expose_ports(&self) -> &[ContainerPort] {
60 &[CLICKHOUSE_PORT]
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use clickhouse::Row;
67 use reqwest::Client;
68 use serde::Deserialize;
69
70 use crate::{clickhouse::ClickHouse as ClickhouseImage, testcontainers::runners::AsyncRunner};
71
72 #[tokio::test]
73 async fn clickhouse_db() -> Result<(), Box<dyn std::error::Error + 'static>> {
74 let clickhouse = ClickhouseImage::default();
75 let node = clickhouse.start().await?;
76
77 let host = node.get_host().await?;
78 let port = node.get_host_port_ipv4(8123).await?;
79 let url = format!("http://{}:{}", host, port);
80
81 let response = Client::new().get(format!("{}/ping", url)).send().await?;
84 assert_eq!(response.status(), 200);
85
86 let query = "CREATE TABLE t (a UInt8) ENGINE = Memory";
88 let response = Client::new().post(url.clone()).body(query).send().await?;
89 assert_eq!(response.status(), 200);
90
91 let query = "INSERT INTO t VALUES (1),(2),(3)";
93 let response = Client::new().post(url.clone()).body(query).send().await?;
94 assert_eq!(response.status(), 200);
95
96 let query = "SELECT * FROM t";
98 let response = Client::new().post(url.clone()).body(query).send().await?;
99 assert_eq!(response.status(), 200);
100
101 let client = clickhouse::Client::default().with_url(format!("http://{host}:{port}"));
102 #[derive(Row, Deserialize)]
103 struct MyRow {
104 #[serde(rename = "a")] _a: u8,
106 }
107 let rows = client.query("SELECT * FROM t").fetch_all::<MyRow>().await?;
108 assert_eq!(rows.len(), 3);
109
110 Ok(())
111 }
112}