1use std::collections::{HashMap, HashSet};
16use std::path::Path;
17use std::sync::{Mutex, OnceLock};
18
19use serde::Serialize;
20use tinytemplate::TinyTemplate;
21
22use crate::cmd::bare::ServerAddr;
23use crate::cmd::compat_case::Version;
24use crate::env::bare::{Env, GreptimeDBContext, ServiceProvider};
25use crate::util;
26
27const DEFAULT_LOG_LEVEL: &str = "--log-level=debug,hyper=warn,tower=warn,datafusion=warn,reqwest=warn,sqlparser=warn,h2=info,opendal=info";
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
36pub enum GrpcArgStyle {
37 Grpc,
39 Rpc,
41}
42
43impl GrpcArgStyle {
44 pub(crate) fn for_version(version: Option<&Version>) -> Self {
49 const GRPC_ARG_RENAME_VERSION: Version = Version {
50 major: 1,
51 minor: 1,
52 patch: 0,
53 };
54
55 if version.is_some_and(|version| version < &GRPC_ARG_RENAME_VERSION) {
56 GrpcArgStyle::Rpc
57 } else {
58 GrpcArgStyle::Grpc
59 }
60 }
61
62 pub fn bind_addr_arg(self) -> &'static str {
64 match self {
65 GrpcArgStyle::Grpc => "--grpc-bind-addr",
66 GrpcArgStyle::Rpc => "--rpc-bind-addr",
67 }
68 }
69
70 pub fn server_addr_arg(self) -> &'static str {
72 match self {
73 GrpcArgStyle::Grpc => "--grpc-server-addr",
74 GrpcArgStyle::Rpc => "--rpc-server-addr",
75 }
76 }
77}
78
79static USED_PORTS: OnceLock<Mutex<HashSet<u16>>> = OnceLock::new();
80
81fn get_used_ports() -> &'static Mutex<HashSet<u16>> {
82 USED_PORTS.get_or_init(|| Mutex::new(HashSet::new()))
83}
84
85fn get_unique_random_port() -> u16 {
86 const MAX_ATTEMPTS: usize = 100;
88
89 for _ in 0..MAX_ATTEMPTS {
90 let p = util::get_random_port();
91 let mut used = get_used_ports().lock().unwrap();
92 if !used.contains(&p) {
93 used.insert(p);
94 return p;
95 }
96 }
97
98 panic!(
99 "Failed to find an unused port after {} attempts",
100 MAX_ATTEMPTS
101 );
102}
103
104#[derive(Clone)]
105pub enum ServerMode {
106 Standalone {
107 http_addr: String,
108 rpc_bind_addr: String,
109 mysql_addr: String,
110 postgres_addr: String,
111 },
112 Frontend {
113 http_addr: String,
114 rpc_bind_addr: String,
115 mysql_addr: String,
116 postgres_addr: String,
117 metasrv_addr: String,
118 },
119 Metasrv {
120 rpc_bind_addr: String,
121 rpc_server_addr: String,
122 http_addr: String,
123 },
124 Datanode {
125 rpc_bind_addr: String,
126 rpc_server_addr: String,
127 http_addr: String,
128 metasrv_addr: String,
129 node_id: u32,
130 },
131 Flownode {
132 rpc_bind_addr: String,
133 rpc_server_addr: String,
134 http_addr: String,
135 metasrv_addr: String,
136 node_id: u32,
137 },
138}
139
140#[derive(Serialize)]
141struct ConfigContext {
142 wal_dir: String,
143 data_home: String,
144 procedure_dir: String,
145 is_raft_engine: bool,
146 kafka_wal_broker_endpoints: String,
147 use_etcd: bool,
148 store_addrs: String,
149 instance_id: usize,
150 addrs: HashMap<String, String>,
151 enable_flat_format: bool,
153 enable_gc: bool,
155}
156
157impl ServerMode {
158 pub fn random_standalone() -> Self {
159 let http_port = get_unique_random_port();
160 let rpc_port = get_unique_random_port();
161 let mysql_port = get_unique_random_port();
162 let postgres_port = get_unique_random_port();
163
164 ServerMode::Standalone {
165 http_addr: format!("127.0.0.1:{http_port}"),
166 rpc_bind_addr: format!("127.0.0.1:{rpc_port}"),
167 mysql_addr: format!("127.0.0.1:{mysql_port}"),
168 postgres_addr: format!("127.0.0.1:{postgres_port}"),
169 }
170 }
171
172 pub fn random_frontend(metasrv_port: u16) -> Self {
173 let http_port = get_unique_random_port();
174 let rpc_port = get_unique_random_port();
175 let mysql_port = get_unique_random_port();
176 let postgres_port = get_unique_random_port();
177
178 ServerMode::Frontend {
179 http_addr: format!("127.0.0.1:{http_port}"),
180 rpc_bind_addr: format!("127.0.0.1:{rpc_port}"),
181 mysql_addr: format!("127.0.0.1:{mysql_port}"),
182 postgres_addr: format!("127.0.0.1:{postgres_port}"),
183 metasrv_addr: format!("127.0.0.1:{metasrv_port}"),
184 }
185 }
186
187 pub fn random_metasrv() -> Self {
188 let bind_port = get_unique_random_port();
189 let http_port = get_unique_random_port();
190
191 ServerMode::Metasrv {
192 rpc_bind_addr: format!("127.0.0.1:{bind_port}"),
193 rpc_server_addr: format!("127.0.0.1:{bind_port}"),
194 http_addr: format!("127.0.0.1:{http_port}"),
195 }
196 }
197
198 pub fn random_datanode(metasrv_port: u16, node_id: u32) -> Self {
199 let rpc_port = get_unique_random_port();
200 let http_port = get_unique_random_port();
201
202 ServerMode::Datanode {
203 rpc_bind_addr: format!("127.0.0.1:{rpc_port}"),
204 rpc_server_addr: format!("127.0.0.1:{rpc_port}"),
205 http_addr: format!("127.0.0.1:{http_port}"),
206 metasrv_addr: format!("127.0.0.1:{metasrv_port}"),
207 node_id,
208 }
209 }
210
211 pub fn random_flownode(metasrv_port: u16, node_id: u32) -> Self {
212 let rpc_port = get_unique_random_port();
213 let http_port = get_unique_random_port();
214
215 ServerMode::Flownode {
216 rpc_bind_addr: format!("127.0.0.1:{rpc_port}"),
217 rpc_server_addr: format!("127.0.0.1:{rpc_port}"),
218 http_addr: format!("127.0.0.1:{http_port}"),
219 metasrv_addr: format!("127.0.0.1:{metasrv_port}"),
220 node_id,
221 }
222 }
223
224 pub fn name(&self) -> &'static str {
225 match self {
226 ServerMode::Standalone { .. } => "standalone",
227 ServerMode::Frontend { .. } => "frontend",
228 ServerMode::Metasrv { .. } => "metasrv",
229 ServerMode::Datanode { .. } => "datanode",
230 ServerMode::Flownode { .. } => "flownode",
231 }
232 }
233
234 pub fn check_addrs(&self) -> Vec<String> {
236 match self {
237 ServerMode::Standalone {
238 rpc_bind_addr,
239 mysql_addr,
240 postgres_addr,
241 http_addr,
242 ..
243 } => {
244 vec![
245 rpc_bind_addr.clone(),
246 mysql_addr.clone(),
247 postgres_addr.clone(),
248 http_addr.clone(),
249 ]
250 }
251 ServerMode::Frontend {
252 rpc_bind_addr,
253 mysql_addr,
254 postgres_addr,
255 ..
256 } => {
257 vec![
258 rpc_bind_addr.clone(),
259 mysql_addr.clone(),
260 postgres_addr.clone(),
261 ]
262 }
263 ServerMode::Metasrv { rpc_bind_addr, .. } => {
264 vec![rpc_bind_addr.clone()]
265 }
266 ServerMode::Datanode { rpc_bind_addr, .. } => {
267 vec![rpc_bind_addr.clone()]
268 }
269 ServerMode::Flownode { rpc_bind_addr, .. } => {
270 vec![rpc_bind_addr.clone()]
271 }
272 }
273 }
274
275 pub fn server_addr(&self) -> Option<ServerAddr> {
277 match self {
278 ServerMode::Standalone {
279 rpc_bind_addr,
280 mysql_addr,
281 postgres_addr,
282 ..
283 } => Some(ServerAddr {
284 server_addr: Some(rpc_bind_addr.clone()),
285 pg_server_addr: Some(postgres_addr.clone()),
286 mysql_server_addr: Some(mysql_addr.clone()),
287 }),
288 ServerMode::Frontend {
289 rpc_bind_addr,
290 mysql_addr,
291 postgres_addr,
292 ..
293 } => Some(ServerAddr {
294 server_addr: Some(rpc_bind_addr.clone()),
295 pg_server_addr: Some(postgres_addr.clone()),
296 mysql_server_addr: Some(mysql_addr.clone()),
297 }),
298 _ => None,
299 }
300 }
301
302 pub fn generate_config_file(
303 &self,
304 sqlness_home: &Path,
305 db_ctx: &GreptimeDBContext,
306 id: usize,
307 ) -> String {
308 let mut tt = TinyTemplate::new();
309
310 let mut path = util::sqlness_conf_path();
311 path.push(format!("{}-test.toml.template", self.name()));
312 let template = std::fs::read_to_string(&path)
313 .unwrap_or_else(|e| panic!("read file '{}' error: {e}", path.display()));
314 tt.add_template(self.name(), &template).unwrap();
315
316 let data_home = sqlness_home.join(format!("greptimedb-{}-{}", id, self.name()));
317 std::fs::create_dir_all(data_home.as_path()).unwrap();
318
319 let wal_dir = data_home.join("wal").display().to_string();
320 let procedure_dir = data_home.join("procedure").display().to_string();
321
322 let addrs: HashMap<String, String> = match self {
324 ServerMode::Standalone {
325 rpc_bind_addr,
326 mysql_addr,
327 postgres_addr,
328 http_addr,
329 } => [
330 ("http_addr".to_string(), http_addr.clone()),
331 ("grpc_addr".to_string(), rpc_bind_addr.clone()),
332 ("mysql_addr".to_string(), mysql_addr.clone()),
333 ("postgres_addr".to_string(), postgres_addr.clone()),
334 ]
335 .into(),
336 ServerMode::Frontend { rpc_bind_addr, .. } => {
337 [("grpc_addr".to_string(), rpc_bind_addr.clone())].into()
338 }
339 ServerMode::Datanode { metasrv_addr, .. } => {
340 [("metasrv_addr".to_string(), metasrv_addr.clone())].into()
341 }
342 _ => HashMap::new(),
343 };
344
345 let ctx = ConfigContext {
346 wal_dir,
347 data_home: data_home.display().to_string(),
348 procedure_dir,
349 is_raft_engine: db_ctx.is_raft_engine(),
350 kafka_wal_broker_endpoints: db_ctx.kafka_wal_broker_endpoints(),
351 use_etcd: !db_ctx.store_config().store_addrs.is_empty(),
352 store_addrs: db_ctx
353 .store_config()
354 .store_addrs
355 .iter()
356 .map(|p| format!("\"{p}\""))
357 .collect::<Vec<_>>()
358 .join(","),
359 instance_id: id,
360 addrs,
361 enable_flat_format: db_ctx.store_config().enable_flat_format,
362 enable_gc: db_ctx.store_config().enable_gc,
363 };
364
365 let rendered = tt.render(self.name(), &ctx).unwrap();
366
367 let conf_file = data_home
368 .join(format!("{}-{}-{}.toml", self.name(), id, db_ctx.time()))
369 .display()
370 .to_string();
371 println!(
372 "Generating id {}, {} config file in {conf_file}",
373 id,
374 self.name()
375 );
376 std::fs::write(&conf_file, rendered).unwrap();
377
378 conf_file
379 }
380
381 pub fn get_args(
382 &self,
383 sqlness_home: &Path,
384 env: &Env,
385 db_ctx: &GreptimeDBContext,
386 id: usize,
387 arg_style: GrpcArgStyle,
388 ) -> Vec<String> {
389 let mut args = env
390 .extra_args()
391 .iter()
392 .map(String::as_str)
393 .chain([DEFAULT_LOG_LEVEL, self.name(), "start"])
394 .map(ToString::to_string)
395 .collect::<Vec<String>>();
396
397 match self {
398 ServerMode::Standalone {
399 http_addr,
400 rpc_bind_addr,
401 mysql_addr,
402 postgres_addr,
403 } => {
404 args.extend([
405 format!(
406 "--log-dir={}/greptimedb-{}-standalone/logs",
407 sqlness_home.display(),
408 id
409 ),
410 "-c".to_string(),
411 self.generate_config_file(sqlness_home, db_ctx, id),
412 format!("--http-addr={http_addr}"),
413 format!("{}={rpc_bind_addr}", arg_style.bind_addr_arg()),
414 format!("--mysql-addr={mysql_addr}"),
415 format!("--postgres-addr={postgres_addr}"),
416 ]);
417 }
418 ServerMode::Frontend {
419 http_addr,
420 rpc_bind_addr,
421 mysql_addr,
422 postgres_addr,
423 metasrv_addr,
424 } => {
425 args.extend([
426 format!("--metasrv-addrs={metasrv_addr}"),
427 format!("--http-addr={http_addr}"),
428 format!("{}={rpc_bind_addr}", arg_style.bind_addr_arg()),
429 format!("{}={rpc_bind_addr}", arg_style.server_addr_arg()),
432 format!("--mysql-addr={mysql_addr}"),
433 format!("--postgres-addr={postgres_addr}"),
434 format!(
435 "--log-dir={}/greptimedb-{}-frontend/logs",
436 sqlness_home.display(),
437 id
438 ),
439 "-c".to_string(),
440 self.generate_config_file(sqlness_home, db_ctx, id),
441 ]);
442 }
443 ServerMode::Metasrv {
444 rpc_bind_addr,
445 rpc_server_addr,
446 http_addr,
447 } => {
448 args.extend([
449 arg_style.bind_addr_arg().to_string(),
450 rpc_bind_addr.clone(),
451 arg_style.server_addr_arg().to_string(),
452 rpc_server_addr.clone(),
453 "--enable-region-failover".to_string(),
454 "false".to_string(),
455 format!("--http-addr={http_addr}"),
456 format!(
457 "--log-dir={}/greptimedb-{}-metasrv/logs",
458 sqlness_home.display(),
459 id
460 ),
461 "-c".to_string(),
462 self.generate_config_file(sqlness_home, db_ctx, id),
463 ]);
464
465 if matches!(
466 db_ctx.store_config().setup_pg,
467 Some(ServiceProvider::Create)
468 ) {
469 let client_ports = db_ctx
470 .store_config()
471 .store_addrs
472 .iter()
473 .map(|s| s.split(':').nth(1).unwrap().parse::<u16>().unwrap())
474 .collect::<Vec<_>>();
475 let client_port = client_ports.first().unwrap_or(&5432);
476 let pg_server_addr = format!(
477 "postgresql://greptimedb:admin@127.0.0.1:{}/postgres",
478 client_port
479 );
480 args.extend(vec!["--backend".to_string(), "postgres-store".to_string()]);
481 args.extend(vec!["--store-addrs".to_string(), pg_server_addr]);
482 } else if let Some(ServiceProvider::External(connection_string)) =
483 db_ctx.store_config().setup_pg
484 {
485 println!("Using external PostgreSQL '{connection_string}' as Kvbackend");
486 args.extend([
487 "--backend".to_string(),
488 "postgres-store".to_string(),
489 "--store-addrs".to_string(),
490 connection_string,
491 ]);
492 } else if matches!(
493 db_ctx.store_config().setup_mysql,
494 Some(ServiceProvider::Create)
495 ) {
496 let client_ports = db_ctx
497 .store_config()
498 .store_addrs
499 .iter()
500 .map(|s| s.split(':').nth(1).unwrap().parse::<u16>().unwrap())
501 .collect::<Vec<_>>();
502 let client_port = client_ports.first().unwrap_or(&3306);
503 let mysql_server_addr =
504 format!("mysql://greptimedb:admin@127.0.0.1:{}/mysql", client_port);
505 args.extend(vec!["--backend".to_string(), "mysql-store".to_string()]);
506 args.extend(vec!["--store-addrs".to_string(), mysql_server_addr]);
507 } else if let Some(ServiceProvider::External(connection_string)) =
508 db_ctx.store_config().setup_mysql
509 {
510 println!("Using external MySQL '{connection_string}' as Kvbackend");
511 args.extend([
512 "--backend".to_string(),
513 "mysql-store".to_string(),
514 "--store-addrs".to_string(),
515 connection_string,
516 ]);
517 } else if db_ctx.store_config().store_addrs.is_empty() {
518 args.extend(vec!["--backend".to_string(), "memory-store".to_string()])
519 }
520 }
521 ServerMode::Datanode {
522 rpc_bind_addr,
523 rpc_server_addr,
524 http_addr,
525 metasrv_addr,
526 node_id,
527 } => {
528 let data_home = sqlness_home.join(format!(
529 "greptimedb_{}_datanode_{}_{node_id}",
530 id,
531 db_ctx.time()
532 ));
533 args.extend([
534 format!("{}={rpc_bind_addr}", arg_style.bind_addr_arg()),
535 format!("{}={rpc_server_addr}", arg_style.server_addr_arg()),
536 format!("--http-addr={http_addr}"),
537 format!("--data-home={}", data_home.display()),
538 format!("--log-dir={}/logs", data_home.display()),
539 format!("--node-id={node_id}"),
540 "-c".to_string(),
541 self.generate_config_file(sqlness_home, db_ctx, id),
542 format!("--metasrv-addrs={metasrv_addr}"),
543 ]);
544 }
545 ServerMode::Flownode {
546 rpc_bind_addr,
547 rpc_server_addr,
548 http_addr,
549 metasrv_addr,
550 node_id,
551 } => {
552 args.extend([
553 format!("{}={rpc_bind_addr}", arg_style.bind_addr_arg()),
554 format!("{}={rpc_server_addr}", arg_style.server_addr_arg()),
555 format!("--node-id={node_id}"),
556 format!(
557 "--log-dir={}/greptimedb-{}-flownode/logs",
558 sqlness_home.display(),
559 id
560 ),
561 format!("--metasrv-addrs={metasrv_addr}"),
562 format!("--http-addr={http_addr}"),
563 ]);
564 }
565 }
566
567 args
568 }
569}
570
571#[cfg(test)]
572mod tests {
573 use std::path::PathBuf;
574
575 use super::*;
576 use crate::env::bare::{StoreConfig, WalConfig};
577
578 fn test_env(sqlness_home: &Path) -> (Env, GreptimeDBContext) {
579 let store_config = StoreConfig {
580 store_addrs: vec!["127.0.0.1:2379".to_string()],
581 setup_etcd: true,
582 setup_pg: None,
583 setup_mysql: None,
584 enable_flat_format: false,
585 enable_gc: false,
586 };
587 let env = Env::new(
588 sqlness_home.to_path_buf(),
589 ServerAddr::default(),
590 WalConfig::RaftEngine,
591 false,
592 Some(PathBuf::from(".")),
593 store_config.clone(),
594 vec![],
595 );
596 let db_ctx = GreptimeDBContext::new(WalConfig::RaftEngine, store_config);
597
598 (env, db_ctx)
599 }
600
601 fn has_arg(args: &[String], name: &str) -> bool {
602 let prefix = format!("{name}=");
603 args.iter()
604 .any(|arg| arg == name || arg.starts_with(&prefix))
605 }
606
607 fn assert_uses_style(args: &[String], style: GrpcArgStyle, expect_server_addr: bool) {
608 let bind = style.bind_addr_arg();
609 let server = style.server_addr_arg();
610 let other_bind = match style {
611 GrpcArgStyle::Grpc => "--rpc-bind-addr",
612 GrpcArgStyle::Rpc => "--grpc-bind-addr",
613 };
614 let other_server = match style {
615 GrpcArgStyle::Grpc => "--rpc-server-addr",
616 GrpcArgStyle::Rpc => "--grpc-server-addr",
617 };
618
619 assert!(has_arg(args, bind), "missing {bind} in args: {args:?}");
620 assert!(
621 !args.iter().any(|arg| arg.contains(other_bind)),
622 "unexpected {other_bind} in args: {args:?}"
623 );
624
625 if expect_server_addr {
626 assert!(has_arg(args, server), "missing {server} in args: {args:?}");
627 assert!(
628 !args.iter().any(|arg| arg.contains(other_server)),
629 "unexpected {other_server} in args: {args:?}"
630 );
631 }
632 }
633
634 fn test_all_modes(env: &Env, db_ctx: &GreptimeDBContext, temp_dir: &Path, style: GrpcArgStyle) {
635 let standalone = ServerMode::Standalone {
636 http_addr: "127.0.0.1:4000".to_string(),
637 rpc_bind_addr: "127.0.0.1:4001".to_string(),
638 mysql_addr: "127.0.0.1:4002".to_string(),
639 postgres_addr: "127.0.0.1:4003".to_string(),
640 };
641 assert_uses_style(
642 &standalone.get_args(temp_dir, env, db_ctx, 0, style),
643 style,
644 false,
645 );
646
647 let frontend = ServerMode::Frontend {
648 http_addr: "127.0.0.1:4100".to_string(),
649 rpc_bind_addr: "127.0.0.1:4101".to_string(),
650 mysql_addr: "127.0.0.1:4102".to_string(),
651 postgres_addr: "127.0.0.1:4103".to_string(),
652 metasrv_addr: "127.0.0.1:4001".to_string(),
653 };
654 assert_uses_style(
655 &frontend.get_args(temp_dir, env, db_ctx, 0, style),
656 style,
657 true,
658 );
659
660 let metasrv = ServerMode::Metasrv {
661 rpc_bind_addr: "127.0.0.1:4201".to_string(),
662 rpc_server_addr: "127.0.0.1:4201".to_string(),
663 http_addr: "127.0.0.1:4200".to_string(),
664 };
665 assert_uses_style(
666 &metasrv.get_args(temp_dir, env, db_ctx, 0, style),
667 style,
668 true,
669 );
670
671 let datanode = ServerMode::Datanode {
672 rpc_bind_addr: "127.0.0.1:4301".to_string(),
673 rpc_server_addr: "127.0.0.1:4301".to_string(),
674 http_addr: "127.0.0.1:4300".to_string(),
675 metasrv_addr: "127.0.0.1:4001".to_string(),
676 node_id: 0,
677 };
678 assert_uses_style(
679 &datanode.get_args(temp_dir, env, db_ctx, 0, style),
680 style,
681 true,
682 );
683
684 let flownode = ServerMode::Flownode {
685 rpc_bind_addr: "127.0.0.1:4401".to_string(),
686 rpc_server_addr: "127.0.0.1:4401".to_string(),
687 http_addr: "127.0.0.1:4400".to_string(),
688 metasrv_addr: "127.0.0.1:4001".to_string(),
689 node_id: 0,
690 };
691 assert_uses_style(
692 &flownode.get_args(temp_dir, env, db_ctx, 0, style),
693 style,
694 true,
695 );
696 }
697
698 #[test]
699 fn test_get_args_with_grpc_style() {
700 let temp_dir = tempfile::tempdir().unwrap();
701 let (env, db_ctx) = test_env(temp_dir.path());
702 test_all_modes(&env, &db_ctx, temp_dir.path(), GrpcArgStyle::Grpc);
703 }
704
705 #[test]
706 fn test_get_args_with_rpc_style() {
707 let temp_dir = tempfile::tempdir().unwrap();
708 let (env, db_ctx) = test_env(temp_dir.path());
709 test_all_modes(&env, &db_ctx, temp_dir.path(), GrpcArgStyle::Rpc);
710 }
711
712 #[test]
713 fn test_arg_style_for_unknown_version_defaults_to_grpc() {
714 assert_eq!(GrpcArgStyle::for_version(None), GrpcArgStyle::Grpc);
715 }
716
717 #[test]
718 fn test_arg_style_for_legacy_versions_uses_rpc() {
719 let v1_0_0 = Version::parse("v1.0.0").unwrap();
720 let v1_0_9 = Version::parse("v1.0.9").unwrap();
721
722 assert_eq!(GrpcArgStyle::for_version(Some(&v1_0_0)), GrpcArgStyle::Rpc);
723 assert_eq!(GrpcArgStyle::for_version(Some(&v1_0_9)), GrpcArgStyle::Rpc);
724 }
725
726 #[test]
727 fn test_arg_style_for_current_versions_uses_grpc() {
728 let v1_1_0 = Version::parse("v1.1.0").unwrap();
729 let v1_2_0 = Version::parse("v1.2.0").unwrap();
730
731 assert_eq!(GrpcArgStyle::for_version(Some(&v1_1_0)), GrpcArgStyle::Grpc);
732 assert_eq!(GrpcArgStyle::for_version(Some(&v1_2_0)), GrpcArgStyle::Grpc);
733 }
734
735 #[test]
736 fn test_generate_distributed_gc_config_when_enabled() {
737 let temp_dir = tempfile::tempdir().unwrap();
738 let store_config = StoreConfig {
739 store_addrs: vec![],
740 setup_etcd: false,
741 setup_pg: None,
742 setup_mysql: None,
743 enable_flat_format: false,
744 enable_gc: true,
745 };
746 let db_ctx = GreptimeDBContext::new(WalConfig::RaftEngine, store_config);
747 let metasrv = ServerMode::Metasrv {
748 rpc_bind_addr: "127.0.0.1:4201".to_string(),
749 rpc_server_addr: "127.0.0.1:4201".to_string(),
750 http_addr: "127.0.0.1:4200".to_string(),
751 };
752 let datanode = ServerMode::Datanode {
753 rpc_bind_addr: "127.0.0.1:4301".to_string(),
754 rpc_server_addr: "127.0.0.1:4301".to_string(),
755 http_addr: "127.0.0.1:4300".to_string(),
756 metasrv_addr: "127.0.0.1:4201".to_string(),
757 node_id: 0,
758 };
759
760 let metasrv_config =
761 std::fs::read_to_string(metasrv.generate_config_file(temp_dir.path(), &db_ctx, 0))
762 .unwrap();
763 let datanode_config =
764 std::fs::read_to_string(datanode.generate_config_file(temp_dir.path(), &db_ctx, 0))
765 .unwrap();
766
767 assert!(metasrv_config.contains("[gc]\nenable = true"));
768 assert!(metasrv_config.contains("[gc.experimental_soft_drop]\nenable = true"));
769 assert!(datanode_config.contains("[region_engine.mito.gc]\nenable = true"));
770 }
771}