sqlness_runner/cmd/
bare.rs1use std::path::PathBuf;
16use std::sync::Arc;
17
18use clap::{Parser, ValueEnum};
19use sqlness::interceptor::Registry;
20use sqlness::{ConfigBuilder, Runner};
21
22use crate::cmd::SqlnessConfig;
23use crate::env::bare::{Env, ServiceProvider, StoreConfig, WalConfig};
24use crate::{protocol_interceptor, util};
25
26#[derive(ValueEnum, Debug, Clone)]
27#[clap(rename_all = "snake_case")]
28enum Wal {
29 RaftEngine,
30 Kafka,
31}
32
33#[derive(clap::Args, Debug, Clone, Default)]
35pub(crate) struct ServerAddr {
36 #[clap(short, long)]
38 pub(crate) server_addr: Option<String>,
39
40 #[clap(short, long, requires = "server_addr")]
42 pub(crate) pg_server_addr: Option<String>,
43
44 #[clap(short, long, requires = "server_addr")]
46 pub(crate) mysql_server_addr: Option<String>,
47}
48
49#[derive(Debug, Parser)]
50pub struct BareCommand {
52 #[clap(flatten)]
53 config: SqlnessConfig,
54
55 #[command(flatten)]
57 server_addr: ServerAddr,
58
59 #[clap(short, long, default_value = "raft_engine")]
61 wal: Wal,
62
63 #[clap(short, long)]
66 kafka_wal_broker_endpoints: Option<String>,
67
68 #[clap(long)]
71 bins_dir: Option<PathBuf>,
72
73 #[clap(long)]
76 preserve_state: bool,
77
78 #[clap(long, default_value = "true")]
80 pull_version_on_need: bool,
81
82 #[clap(long)]
84 store_addrs: Vec<String>,
85
86 #[clap(long, default_value = "false")]
88 setup_etcd: bool,
89
90 #[clap(long, default_missing_value = "", num_args(0..=1))]
92 setup_pg: Option<ServiceProvider>,
93
94 #[clap(long, default_missing_value = "", num_args(0..=1))]
96 setup_mysql: Option<ServiceProvider>,
97
98 #[clap(short, long, default_value = "0")]
100 jobs: usize,
101
102 #[clap(long)]
104 extra_args: Vec<String>,
105
106 #[clap(long, default_value = "false")]
108 enable_flat_format: bool,
109
110 #[clap(long, default_value = "false")]
112 enable_gc: bool,
113}
114
115impl BareCommand {
116 pub async fn run(mut self) {
117 let temp_dir = tempfile::Builder::new()
118 .prefix("sqlness")
119 .tempdir()
120 .unwrap();
121 let sqlness_home = temp_dir.keep();
122
123 let mut interceptor_registry: Registry = Default::default();
124 interceptor_registry.register(
125 protocol_interceptor::PREFIX,
126 Arc::new(protocol_interceptor::ProtocolInterceptorFactory),
127 );
128
129 if let Some(d) = &self.config.case_dir
130 && !d.is_dir()
131 {
132 panic!("{} is not a directory", d.display());
133 }
134 if self.jobs == 0 {
135 self.jobs = num_cpus::get() / 2;
136 }
137
138 if self.server_addr.server_addr.is_some()
141 || self.setup_etcd
142 || self.setup_pg.is_some()
143 || self.setup_mysql.is_some()
144 || matches!(self.wal, Wal::Kafka)
145 || self.kafka_wal_broker_endpoints.is_some()
146 || self.config.test_filter != ".*"
147 {
148 self.jobs = 1;
149 println!(
150 "Normalizing parallelism to 1 due to server addresses, etcd/pg/mysql/kafka setup, or test filter usage"
151 );
152 }
153
154 let config = ConfigBuilder::default()
155 .case_dir(util::get_case_dir(self.config.case_dir))
156 .fail_fast(self.config.fail_fast)
157 .test_filter(self.config.test_filter)
158 .follow_links(true)
159 .env_config_file(self.config.env_config_file)
160 .interceptor_registry(interceptor_registry)
161 .parallelism(self.jobs)
162 .env_parallelism(self.jobs)
163 .build()
164 .unwrap();
165
166 let wal = match self.wal {
167 Wal::RaftEngine => WalConfig::RaftEngine,
168 Wal::Kafka => WalConfig::Kafka {
169 needs_kafka_cluster: self.kafka_wal_broker_endpoints.is_none(),
170 broker_endpoints: self
171 .kafka_wal_broker_endpoints
172 .map(|s| s.split(',').map(|s| s.to_string()).collect())
173 .unwrap_or(vec!["127.0.0.1:9092".to_string()]),
175 },
176 };
177
178 let store = StoreConfig {
179 store_addrs: self.store_addrs.clone(),
180 setup_etcd: self.setup_etcd,
181 setup_pg: self.setup_pg,
182 setup_mysql: self.setup_mysql,
183 enable_flat_format: self.enable_flat_format,
184 enable_gc: self.enable_gc,
185 };
186
187 let runner = Runner::new(
188 config,
189 Env::new(
190 sqlness_home.clone(),
191 self.server_addr,
192 wal,
193 self.pull_version_on_need,
194 self.bins_dir,
195 store,
196 self.extra_args,
197 ),
198 );
199 match runner.run().await {
200 Ok(_) => println!("\x1b[32mAll sqlness tests passed!\x1b[0m"),
201 Err(e) => {
202 println!("\x1b[31mTest failed: {}\x1b[0m", e);
203 std::process::exit(1);
204 }
205 }
206
207 if !self.preserve_state {
209 if self.setup_etcd {
210 println!("Stopping etcd");
211 util::stop_rm_etcd();
212 }
213 println!("Removing state in {:?}", sqlness_home);
215 tokio::fs::remove_dir_all(sqlness_home).await.unwrap();
216 }
217 }
218}