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("/")
50 .with_port(CLICKHOUSE_PORT)
51 .with_expected_status_code(200_u16),
52 )]
53 }
54
55 fn env_vars(
56 &self,
57 ) -> impl IntoIterator<Item = (impl Into<Cow<'_, str>>, impl Into<Cow<'_, str>>)> {
58 &self.env_vars
59 }
60
61 fn expose_ports(&self) -> &[ContainerPort] {
62 &[CLICKHOUSE_PORT]
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use clickhouse::Row;
69 use reqwest::Client;
70 use serde::Deserialize;
71
72 use crate::{clickhouse::ClickHouse as ClickhouseImage, testcontainers::runners::AsyncRunner};
73
74 #[tokio::test]
75 async fn clickhouse_db() -> Result<(), Box<dyn std::error::Error + 'static>> {
76 let clickhouse = ClickhouseImage::default();
77 let node = clickhouse.start().await?;
78
79 let host = node.get_host().await?;
80 let port = node.get_host_port_ipv4(8123).await?;
81 let url = format!("http://{}:{}", host, port);
82
83 let response = Client::new().get(format!("{}/ping", url)).send().await?;
86 assert_eq!(response.status(), 200);
87
88 let query = "CREATE TABLE t (a UInt8) ENGINE = Memory";
90 let response = Client::new().post(url.clone()).body(query).send().await?;
91 assert_eq!(response.status(), 200);
92
93 let query = "INSERT INTO t VALUES (1),(2),(3)";
95 let response = Client::new().post(url.clone()).body(query).send().await?;
96 assert_eq!(response.status(), 200);
97
98 let query = "SELECT * FROM t";
100 let response = Client::new().post(url.clone()).body(query).send().await?;
101 assert_eq!(response.status(), 200);
102
103 let client = clickhouse::Client::default().with_url(format!("http://{host}:{port}"));
104 #[derive(Row, Deserialize)]
105 struct MyRow {
106 #[serde(rename = "a")] _a: u8,
108 }
109 let rows = client.query("SELECT * FROM t").fetch_all::<MyRow>().await?;
110 assert_eq!(rows.len(), 3);
111
112 Ok(())
113 }
114}