1pub mod cluster_info;
16pub mod config;
17pub mod crd;
18pub mod csv_dump_writer;
20pub mod health;
21pub mod migration;
22pub mod partition;
23pub mod pod_failure;
24pub mod procedure;
25#[cfg(feature = "unstable")]
26pub mod process;
27pub mod retry;
28pub mod sql_dump_writer;
30pub mod wait;
31
32use std::env;
33use std::str::FromStr;
34
35use common_base::readable_size::ReadableSize;
36use common_telemetry::info;
37use common_telemetry::tracing::log::LevelFilter;
38use paste::paste;
39use snafu::ResultExt;
40use sqlx::mysql::{MySqlConnectOptions, MySqlPoolOptions};
41use sqlx::{ConnectOptions, MySql, Pool};
42
43use crate::error::{self, Result};
44use crate::ir::Ident;
45
46pub struct Connections {
48 pub mysql: Option<Pool<MySql>>,
49}
50
51const GT_MYSQL_ADDR: &str = "GT_MYSQL_ADDR";
52
53pub async fn init_greptime_connections_via_env() -> Connections {
55 let _ = dotenv::dotenv();
56 let mysql = if let Ok(addr) = env::var(GT_MYSQL_ADDR) {
57 Some(addr)
58 } else {
59 info!("GT_MYSQL_ADDR is empty, ignores test");
60 None
61 };
62
63 init_greptime_connections(mysql).await
64}
65
66pub async fn init_greptime_connections(mysql: Option<String>) -> Connections {
68 let mysql = if let Some(addr) = mysql {
69 let opts = format!("mysql://{addr}/public")
70 .parse::<MySqlConnectOptions>()
71 .unwrap()
72 .log_statements(LevelFilter::Off);
73
74 Some(MySqlPoolOptions::new().connect_with(opts).await.unwrap())
75 } else {
76 None
77 };
78
79 Connections { mysql }
80}
81
82const GT_FUZZ_BINARY_PATH: &str = "GT_FUZZ_BINARY_PATH";
83const GT_FUZZ_INSTANCE_ROOT_DIR: &str = "GT_FUZZ_INSTANCE_ROOT_DIR";
84
85pub struct UnstableTestVariables {
87 pub binary_path: String,
88 pub root_dir: Option<String>,
89}
90
91pub fn load_unstable_test_env_variables() -> UnstableTestVariables {
93 let _ = dotenv::dotenv();
94 let binary_path = env::var(GT_FUZZ_BINARY_PATH).expect("GT_FUZZ_BINARY_PATH not found");
95 let root_dir = env::var(GT_FUZZ_INSTANCE_ROOT_DIR).ok();
96
97 UnstableTestVariables {
98 binary_path,
99 root_dir,
100 }
101}
102
103pub const GT_FUZZ_CLUSTER_NAMESPACE: &str = "GT_FUZZ_CLUSTER_NAMESPACE";
104pub const GT_FUZZ_CLUSTER_NAME: &str = "GT_FUZZ_CLUSTER_NAME";
105
106pub async fn flush_memtable(e: &Pool<MySql>, table_name: &Ident) -> Result<()> {
108 let sql = format!("admin flush_table(\"{}\")", table_name);
109 let result = sqlx::query(&sql)
110 .execute(e)
111 .await
112 .context(error::ExecuteQuerySnafu { sql })?;
113 info!("Flush table: {}\n\nResult: {result:?}\n\n", table_name);
114
115 Ok(())
116}
117
118pub async fn compact_table(e: &Pool<MySql>, table_name: &Ident) -> Result<()> {
120 let sql = format!("admin compact_table(\"{}\")", table_name);
121 let result = sqlx::query(&sql)
122 .execute(e)
123 .await
124 .context(error::ExecuteQuerySnafu { sql })?;
125 info!("Compact table: {}\n\nResult: {result:?}\n\n", table_name);
126
127 Ok(())
128}
129
130pub const GT_FUZZ_INPUT_MAX_ROWS: &str = "GT_FUZZ_INPUT_MAX_ROWS";
131pub const GT_FUZZ_INPUT_MAX_TABLES: &str = "GT_FUZZ_INPUT_MAX_TABLES";
132pub const GT_FUZZ_INPUT_MAX_COLUMNS: &str = "GT_FUZZ_INPUT_MAX_COLUMNS";
133pub const GT_FUZZ_INPUT_MAX_ALTER_ACTIONS: &str = "GT_FUZZ_INPUT_MAX_ALTER_ACTIONS";
134pub const GT_FUZZ_INPUT_MAX_INSERT_ACTIONS: &str = "GT_FUZZ_INPUT_MAX_INSERT_ACTIONS";
135pub const FUZZ_OVERRIDE_PREFIX: &str = "GT_FUZZ_OVERRIDE_";
136pub const GT_FUZZ_DUMP_TABLE_CSV: &str = "GT_FUZZ_DUMP_TABLE_CSV";
138pub const GT_FUZZ_DUMP_DIR: &str = "GT_FUZZ_DUMP_DIR";
140pub const GT_FUZZ_DUMP_SUFFIX: &str = "GT_FUZZ_DUMP_SUFFIX";
142pub const GT_FUZZ_DUMP_BUFFER_MAX_BYTES: &str = "GT_FUZZ_DUMP_BUFFER_MAX_BYTES";
144
145pub fn get_fuzz_override<T>(name: &str) -> Option<T>
147where
148 T: std::str::FromStr,
149{
150 let _ = dotenv::dotenv();
151 let key = format!("{}{}", FUZZ_OVERRIDE_PREFIX, name.to_ascii_uppercase());
152 env::var(&key).ok().and_then(|v| v.parse().ok())
153}
154
155pub fn get_gt_fuzz_dump_dir() -> String {
157 let _ = dotenv::dotenv();
158 env::var(GT_FUZZ_DUMP_DIR).unwrap_or_else(|_| "/tmp/greptime-fuzz-dumps".to_string())
159}
160
161pub fn get_gt_fuzz_dump_suffix() -> String {
163 let _ = dotenv::dotenv();
164 env::var(GT_FUZZ_DUMP_SUFFIX).unwrap_or_else(|_| ".repartition-metric-csv".to_string())
165}
166
167pub fn get_gt_fuzz_dump_buffer_max_bytes() -> usize {
169 let _ = dotenv::dotenv();
170 env::var(GT_FUZZ_DUMP_BUFFER_MAX_BYTES)
171 .ok()
172 .and_then(|value| {
173 value.parse::<usize>().ok().or_else(|| {
174 ReadableSize::from_str(&value)
175 .ok()
176 .map(|size| size.as_bytes() as usize)
177 })
178 })
179 .unwrap_or(8 * 1024 * 1024)
180}
181
182macro_rules! make_get_from_env_helper {
183 ($key:expr, $default: expr) => {
184 paste! {
185 #[doc = "Retrieves `" $key "` environment variable \
186 or returns a default value (`" $default "`) if the environment variable is not set.
187 "]
188 pub fn [<get_ $key:lower>]() -> usize {
189 get_from_env_or_default_value($key, $default)
190 }
191 }
192 };
193}
194
195make_get_from_env_helper!(GT_FUZZ_INPUT_MAX_ALTER_ACTIONS, 256);
196make_get_from_env_helper!(GT_FUZZ_INPUT_MAX_INSERT_ACTIONS, 4);
197make_get_from_env_helper!(GT_FUZZ_INPUT_MAX_ROWS, 512);
198make_get_from_env_helper!(GT_FUZZ_INPUT_MAX_TABLES, 32);
199make_get_from_env_helper!(GT_FUZZ_INPUT_MAX_COLUMNS, 16);
200
201fn get_from_env_or_default_value(key: &str, default_value: usize) -> usize {
204 let _ = dotenv::dotenv();
205 if let Ok(value) = env::var(key) {
206 value.parse().unwrap()
207 } else {
208 default_value
209 }
210}