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