1use std::env;
16use std::fmt::Display;
17use std::net::SocketAddr;
18use std::sync::Arc;
19use std::time::Duration;
20
21use auth::{DefaultPermissionChecker, PermissionCheckerRef, UserProviderRef};
22use axum::Router;
23use catalog::kvbackend::KvBackendCatalogManager;
24use common_base::Plugins;
25use common_config::Configurable;
26use common_meta::key::TableMetadataManager;
27use common_meta::key::catalog_name::CatalogNameKey;
28use common_meta::key::schema_name::SchemaNameKey;
29use common_meta::kv_backend::KvBackendRef;
30use common_query::Output;
31use common_runtime::runtime::BuilderBuild;
32use common_runtime::{Builder as RuntimeBuilder, Runtime};
33use common_test_util::ports;
34use common_test_util::temp_dir::{TempDir, create_temp_dir};
35use common_wal::config::DatanodeWalConfig;
36use datanode::config::{DatanodeOptions, StorageConfig};
37use frontend::instance::Instance;
38use frontend::service_config::{MysqlOptions, PostgresOptions};
39use mito2::gc::GcConfig;
40use object_store::config::{
41 AzblobConfig, FileConfig, GcsConfig, ObjectStoreConfig, OssConfig, S3Config,
42};
43use object_store::services::{Azblob, Gcs, Oss, S3};
44use object_store::test_util::TempFolder;
45use object_store::{AzblobConnection, GcsConnection, ObjectStore, OssConnection, S3Connection};
46use servers::grpc::builder::GrpcServerBuilder;
47use servers::grpc::greptime_handler::GreptimeRequestHandler;
48use servers::grpc::{FlightCompression, GrpcOptions, GrpcServer, GrpcServerConfig};
49use servers::http::{HttpOptions, HttpServerBuilder};
50use servers::metrics_handler::MetricsHandler;
51use servers::mysql::server::{MysqlServer, MysqlSpawnConfig, MysqlSpawnRef};
52use servers::otel_arrow::OtelArrowServiceHandler;
53use servers::pending_rows_batcher::PendingRowsBatcher;
54use servers::postgres::PostgresServer;
55use servers::prom_remote_write::validation::PromValidationMode;
56use servers::query_handler::sql::SqlQueryHandler;
57use servers::request_memory_limiter::ServerMemoryLimiter;
58use servers::server::Server;
59use servers::tls::ReloadableTlsServerConfig;
60use session::context::QueryContext;
61
62use crate::standalone::{GreptimeDbStandalone, GreptimeDbStandaloneBuilder};
63
64pub const PEER_PLACEHOLDER_ADDR: &str = "127.0.0.1:3001";
65
66#[derive(Debug, Clone, Copy, Eq, PartialEq)]
67pub enum StorageType {
68 S3,
69 S3WithCache,
70 File,
71 Oss,
72 Azblob,
73 Gcs,
74}
75
76impl Display for StorageType {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 match self {
79 StorageType::S3 => write!(f, "S3"),
80 StorageType::S3WithCache => write!(f, "S3"),
81 StorageType::File => write!(f, "File"),
82 StorageType::Oss => write!(f, "Oss"),
83 StorageType::Azblob => write!(f, "Azblob"),
84 StorageType::Gcs => write!(f, "Gcs"),
85 }
86 }
87}
88
89impl StorageType {
90 pub fn build_storage_types_based_on_env() -> Vec<StorageType> {
91 let mut storage_types = Vec::with_capacity(4);
92 storage_types.push(StorageType::File);
93 if let Ok(bucket) = env::var("GT_S3_BUCKET")
94 && !bucket.is_empty()
95 {
96 storage_types.push(StorageType::S3);
97 }
98 if env::var("GT_OSS_BUCKET").is_ok() {
99 storage_types.push(StorageType::Oss);
100 }
101 if env::var("GT_AZBLOB_CONTAINER").is_ok() {
102 storage_types.push(StorageType::Azblob);
103 }
104 if env::var("GT_GCS_BUCKET").is_ok() {
105 storage_types.push(StorageType::Gcs);
106 }
107 storage_types
108 }
109
110 pub fn test_on(&self) -> bool {
111 let _ = dotenv::dotenv();
112
113 match self {
114 StorageType::File => true, StorageType::S3 | StorageType::S3WithCache => {
116 if let Ok(b) = env::var("GT_S3_BUCKET") {
117 !b.is_empty()
118 } else {
119 false
120 }
121 }
122 StorageType::Oss => {
123 if let Ok(b) = env::var("GT_OSS_BUCKET") {
124 !b.is_empty()
125 } else {
126 false
127 }
128 }
129 StorageType::Azblob => {
130 if let Ok(b) = env::var("GT_AZBLOB_CONTAINER") {
131 !b.is_empty()
132 } else {
133 false
134 }
135 }
136 StorageType::Gcs => {
137 if let Ok(b) = env::var("GT_GCS_BUCKET") {
138 !b.is_empty()
139 } else {
140 false
141 }
142 }
143 }
144 }
145}
146
147fn s3_test_config() -> S3Config {
148 S3Config {
149 connection: S3Connection {
150 root: uuid::Uuid::new_v4().to_string(),
151 access_key_id: env::var("GT_S3_ACCESS_KEY_ID").unwrap().into(),
152 secret_access_key: env::var("GT_S3_ACCESS_KEY").unwrap().into(),
153 bucket: env::var("GT_S3_BUCKET").unwrap(),
154 region: Some(env::var("GT_S3_REGION").unwrap()),
155 endpoint: env::var("GT_S3_ENDPOINT_URL").ok(),
156 ..Default::default()
157 },
158 ..Default::default()
159 }
160}
161
162pub fn get_test_store_config(store_type: &StorageType) -> (ObjectStoreConfig, TempDirGuard) {
163 let _ = dotenv::dotenv();
164
165 match store_type {
166 StorageType::Gcs => {
167 let gcs_config = GcsConfig {
168 connection: GcsConnection {
169 root: uuid::Uuid::new_v4().to_string(),
170 bucket: env::var("GT_GCS_BUCKET").unwrap(),
171 scope: env::var("GT_GCS_SCOPE").unwrap(),
172 credential_path: env::var("GT_GCS_CREDENTIAL_PATH").unwrap().into(),
173 credential: env::var("GT_GCS_CREDENTIAL").unwrap().into(),
174 endpoint: env::var("GT_GCS_ENDPOINT").unwrap_or_default(),
175 },
176 ..Default::default()
177 };
178
179 let builder = Gcs::from(&gcs_config.connection);
180 let config = ObjectStoreConfig::Gcs(gcs_config);
181 let store = ObjectStore::new(builder).unwrap().finish();
182 (config, TempDirGuard::Gcs(TempFolder::new(&store, "/")))
183 }
184 StorageType::Azblob => {
185 let azblob_config = AzblobConfig {
186 connection: AzblobConnection {
187 root: uuid::Uuid::new_v4().to_string(),
188 container: env::var("GT_AZBLOB_CONTAINER").unwrap(),
189 account_name: env::var("GT_AZBLOB_ACCOUNT_NAME").unwrap().into(),
190 account_key: env::var("GT_AZBLOB_ACCOUNT_KEY").unwrap().into(),
191 endpoint: env::var("GT_AZBLOB_ENDPOINT").unwrap(),
192 ..Default::default()
193 },
194 ..Default::default()
195 };
196
197 let builder = Azblob::from(&azblob_config.connection);
198 let config = ObjectStoreConfig::Azblob(azblob_config);
199 let store = ObjectStore::new(builder).unwrap().finish();
200 (config, TempDirGuard::Azblob(TempFolder::new(&store, "/")))
201 }
202 StorageType::Oss => {
203 let oss_config = OssConfig {
204 connection: OssConnection {
205 root: uuid::Uuid::new_v4().to_string(),
206 access_key_id: env::var("GT_OSS_ACCESS_KEY_ID").unwrap().into(),
207 access_key_secret: env::var("GT_OSS_ACCESS_KEY").unwrap().into(),
208 bucket: env::var("GT_OSS_BUCKET").unwrap(),
209 endpoint: env::var("GT_OSS_ENDPOINT").unwrap(),
210 },
211 ..Default::default()
212 };
213
214 let builder = Oss::from(&oss_config.connection);
215 let config = ObjectStoreConfig::Oss(oss_config);
216 let store = ObjectStore::new(builder).unwrap().finish();
217 (config, TempDirGuard::Oss(TempFolder::new(&store, "/")))
218 }
219 StorageType::S3 | StorageType::S3WithCache => {
220 let mut s3_config = s3_test_config();
221
222 if *store_type == StorageType::S3WithCache {
223 s3_config.cache.cache_path = "/tmp/greptimedb_cache".to_string();
224 } else {
225 s3_config.cache.enable_read_cache = false;
226 }
227
228 let builder = S3::from(&s3_config.connection);
229 let config = ObjectStoreConfig::S3(s3_config);
230 let store = ObjectStore::new(builder).unwrap().finish();
231 (config, TempDirGuard::S3(TempFolder::new(&store, "/")))
232 }
233 StorageType::File => (ObjectStoreConfig::File(FileConfig {}), TempDirGuard::None),
234 }
235}
236
237pub enum TempDirGuard {
238 None,
239 S3(TempFolder),
240 Oss(TempFolder),
241 Azblob(TempFolder),
242 Gcs(TempFolder),
243}
244
245pub struct TestGuard {
246 pub home_guard: FileDirGuard,
247 pub storage_guards: Vec<StorageGuard>,
248}
249
250pub struct FileDirGuard {
251 pub temp_dir: TempDir,
252}
253
254impl FileDirGuard {
255 pub fn new(temp_dir: TempDir) -> Self {
256 Self { temp_dir }
257 }
258}
259
260pub struct StorageGuard(pub TempDirGuard);
261
262impl TestGuard {
263 pub async fn remove_all(&mut self) {
264 for storage_guard in self.storage_guards.iter_mut() {
265 if let TempDirGuard::S3(guard)
266 | TempDirGuard::Oss(guard)
267 | TempDirGuard::Azblob(guard)
268 | TempDirGuard::Gcs(guard) = &mut storage_guard.0
269 {
270 guard.remove_all().await.unwrap()
271 }
272 }
273 }
274}
275
276impl Drop for TestGuard {
277 fn drop(&mut self) {
278 let (tx, rx) = std::sync::mpsc::channel();
279
280 let guards = std::mem::take(&mut self.storage_guards);
281 common_runtime::spawn_global(async move {
282 let mut errors = vec![];
283 for guard in guards {
284 if let TempDirGuard::S3(guard)
285 | TempDirGuard::Oss(guard)
286 | TempDirGuard::Azblob(guard)
287 | TempDirGuard::Gcs(guard) = guard.0
288 && let Err(e) = guard.remove_all().await
289 {
290 errors.push(e);
291 }
292 }
293 if errors.is_empty() {
294 tx.send(Ok(())).unwrap();
295 } else {
296 tx.send(Err(errors)).unwrap();
297 }
298 });
299 rx.recv().unwrap().unwrap_or_else(|e| panic!("{:?}", e));
300 }
301}
302
303pub fn create_tmp_dir_and_datanode_opts(
304 default_store_type: StorageType,
305 store_provider_types: Vec<StorageType>,
306 name: &str,
307 wal_config: DatanodeWalConfig,
308 gc_config: GcConfig,
309) -> (DatanodeOptions, TestGuard) {
310 let home_tmp_dir = create_temp_dir(&format!("gt_data_{name}"));
311 let home_dir = home_tmp_dir.path().to_str().unwrap().to_string();
312
313 let mut store_providers = Vec::with_capacity(store_provider_types.len());
315 let mut storage_guards = Vec::with_capacity(store_provider_types.len() + 1);
317
318 let (default_store, data_tmp_dir) = get_test_store_config(&default_store_type);
319 storage_guards.push(StorageGuard(data_tmp_dir));
320
321 for store_type in store_provider_types {
322 let (store, data_tmp_dir) = get_test_store_config(&store_type);
323 store_providers.push(store);
324 storage_guards.push(StorageGuard(data_tmp_dir))
325 }
326 let opts = create_datanode_opts(
327 default_store,
328 store_providers,
329 home_dir,
330 wal_config,
331 gc_config,
332 );
333
334 (
335 opts,
336 TestGuard {
337 home_guard: FileDirGuard::new(home_tmp_dir),
338 storage_guards,
339 },
340 )
341}
342
343pub(crate) fn create_datanode_opts(
344 default_store: ObjectStoreConfig,
345 providers: Vec<ObjectStoreConfig>,
346 home_dir: String,
347 wal_config: DatanodeWalConfig,
348 gc_config: GcConfig,
349) -> DatanodeOptions {
350 let region_engine = DatanodeOptions::default()
351 .region_engine
352 .into_iter()
353 .map(|mut v| {
354 if let datanode::config::RegionEngineConfig::Mito(mito_config) = &mut v {
355 mito_config.gc = gc_config.clone();
356 }
357 v
358 })
359 .collect();
360 DatanodeOptions {
361 node_id: Some(0),
362 require_lease_before_startup: true,
363 storage: StorageConfig {
364 data_home: home_dir,
365 copy_root: None,
366 providers,
367 store: default_store,
368 },
369 grpc: GrpcOptions::default()
370 .with_bind_addr(PEER_PLACEHOLDER_ADDR)
371 .with_server_addr(PEER_PLACEHOLDER_ADDR),
372 wal: wal_config,
373 region_engine,
374 ..Default::default()
375 }
376}
377
378pub(crate) async fn create_test_table(instance: &Instance, table_name: &str) {
379 let sql = format!(
380 r#"
381CREATE TABLE IF NOT EXISTS {table_name} (
382 host String NOT NULL PRIMARY KEY,
383 cpu DOUBLE NULL,
384 memory DOUBLE NULL,
385 ts TIMESTAMP NOT NULL TIME INDEX,
386)
387"#
388 );
389
390 let result = instance.do_query(&sql, QueryContext::arc()).await;
391 let _ = result.first().unwrap().as_ref().unwrap();
392}
393
394async fn setup_standalone_instance(
395 test_name: &str,
396 store_type: StorageType,
397) -> GreptimeDbStandalone {
398 GreptimeDbStandaloneBuilder::new(test_name)
399 .with_default_store_type(store_type)
400 .build()
401 .await
402}
403
404async fn setup_standalone_instance_with_slow_query_threshold(
405 test_name: &str,
406 store_type: StorageType,
407 slow_query_threshold: std::time::Duration,
408) -> GreptimeDbStandalone {
409 GreptimeDbStandaloneBuilder::new(test_name)
410 .with_default_store_type(store_type)
411 .with_slow_query_threshold(slow_query_threshold)
412 .build()
413 .await
414}
415
416async fn setup_standalone_instance_with_plugins(
417 test_name: &str,
418 store_type: StorageType,
419 plugins: Plugins,
420) -> GreptimeDbStandalone {
421 GreptimeDbStandaloneBuilder::new(test_name)
422 .with_default_store_type(store_type)
423 .with_plugin(plugins)
424 .build()
425 .await
426}
427
428async fn setup_standalone_instance_with_plugins_and_slow_query_threshold(
429 test_name: &str,
430 store_type: StorageType,
431 plugins: Plugins,
432 slow_query_threshold: std::time::Duration,
433) -> GreptimeDbStandalone {
434 GreptimeDbStandaloneBuilder::new(test_name)
435 .with_default_store_type(store_type)
436 .with_plugin(plugins)
437 .with_slow_query_threshold(slow_query_threshold)
438 .build()
439 .await
440}
441
442pub async fn setup_test_http_app(store_type: StorageType, name: &str) -> (Router, TestGuard) {
443 let instance = setup_standalone_instance(name, store_type).await;
444
445 let http_opts = HttpOptions {
446 addr: format!("127.0.0.1:{}", ports::get_port()),
447 ..Default::default()
448 };
449 let http_server = HttpServerBuilder::new(http_opts)
450 .with_sql_handler(instance.fe_instance().clone())
451 .with_logs_handler(instance.fe_instance().clone())
452 .with_metrics_handler(MetricsHandler)
453 .with_greptime_config_options(instance.opts.datanode_options().to_toml().unwrap())
454 .build();
455 (
456 http_server.build(http_server.make_app()).unwrap(),
457 instance.guard,
458 )
459}
460
461pub async fn setup_test_http_app_with_frontend(
462 store_type: StorageType,
463 name: &str,
464) -> (Router, TestGuard) {
465 setup_test_http_app_with_frontend_and_user_provider(store_type, name, None).await
466}
467
468pub async fn setup_test_http_app_with_frontend_and_slow_query_threshold(
469 store_type: StorageType,
470 name: &str,
471 slow_query_threshold: std::time::Duration,
472) -> (Router, TestGuard) {
473 let instance =
474 setup_standalone_instance_with_slow_query_threshold(name, store_type, slow_query_threshold)
475 .await;
476
477 create_test_table(instance.fe_instance(), "demo").await;
478
479 let http_opts = HttpOptions {
480 addr: format!("127.0.0.1:{}", ports::get_port()),
481 ..Default::default()
482 };
483
484 let http_server = HttpServerBuilder::new(http_opts)
485 .with_sql_handler(instance.fe_instance().clone())
486 .with_log_ingest_handler(instance.fe_instance().clone(), None, None)
487 .with_logs_handler(instance.fe_instance().clone())
488 .with_influxdb_handler(instance.fe_instance().clone())
489 .with_otlp_handler(instance.fe_instance().clone(), true)
490 .with_jaeger_handler(instance.fe_instance().clone())
491 .with_greptime_config_options(instance.opts.to_toml().unwrap())
492 .build();
493
494 let app = http_server.build(http_server.make_app()).unwrap();
495 (app, instance.guard)
496}
497
498pub async fn setup_test_http_app_with_frontend_and_user_provider(
499 store_type: StorageType,
500 name: &str,
501 user_provider: Option<UserProviderRef>,
502) -> (Router, TestGuard) {
503 setup_test_http_app_with_frontend_and_custom_options(
504 store_type,
505 name,
506 user_provider,
507 None,
508 None,
509 )
510 .await
511}
512
513pub async fn setup_test_http_app_with_frontend_and_custom_options(
514 store_type: StorageType,
515 name: &str,
516 user_provider: Option<UserProviderRef>,
517 http_opts: Option<HttpOptions>,
518 memory_limiter: Option<ServerMemoryLimiter>,
519) -> (Router, TestGuard) {
520 let plugins = Plugins::new();
521 if let Some(user_provider) = user_provider.clone() {
522 plugins.insert::<UserProviderRef>(user_provider.clone());
523 plugins.insert::<PermissionCheckerRef>(DefaultPermissionChecker::arc());
524 }
525
526 let instance = setup_standalone_instance_with_plugins(name, store_type, plugins).await;
527
528 create_test_table(instance.fe_instance(), "demo").await;
529
530 let http_opts = http_opts.unwrap_or_else(|| HttpOptions {
531 addr: format!("127.0.0.1:{}", ports::get_port()),
532 ..Default::default()
533 });
534
535 let mut http_server = HttpServerBuilder::new(http_opts)
536 .with_sql_handler(instance.fe_instance().clone())
537 .with_log_ingest_handler(instance.fe_instance().clone(), None, None)
538 .with_logs_handler(instance.fe_instance().clone())
539 .with_influxdb_handler(instance.fe_instance().clone())
540 .with_otlp_handler(instance.fe_instance().clone(), true)
541 .with_jaeger_handler(instance.fe_instance().clone())
542 .with_dashboard_handler(instance.fe_instance().clone())
543 .with_greptime_config_options(instance.opts.to_toml().unwrap());
544
545 if let Some(user_provider) = user_provider {
546 http_server = http_server.with_user_provider(user_provider);
547 }
548
549 if let Some(limiter) = memory_limiter {
550 http_server = http_server.with_memory_limiter(limiter);
551 }
552
553 let http_server = http_server.build();
554
555 let app = http_server.build(http_server.make_app()).unwrap();
556 (app, instance.guard)
557}
558
559async fn run_sql(sql: &str, instance: &GreptimeDbStandalone) {
560 let result = instance
561 .fe_instance()
562 .do_query(sql, QueryContext::arc())
563 .await;
564 let _ = result.first().unwrap().as_ref().unwrap();
565}
566
567pub async fn setup_test_prom_app_with_frontend(
568 store_type: StorageType,
569 name: &str,
570) -> (Router, TestGuard) {
571 setup_test_prom_app_with_frontend_inner(store_type, name, false, false).await
572}
573
574pub async fn setup_test_prom_app_with_frontend_native_histogram(
575 store_type: StorageType,
576 name: &str,
577) -> (Router, TestGuard) {
578 setup_test_prom_app_with_frontend_inner(store_type, name, false, true).await
579}
580
581pub async fn setup_test_prom_app_with_frontend_batched(
585 store_type: StorageType,
586 name: &str,
587) -> (Router, TestGuard) {
588 setup_test_prom_app_with_frontend_inner(store_type, name, true, false).await
589}
590
591async fn setup_test_prom_app_with_frontend_inner(
592 store_type: StorageType,
593 name: &str,
594 enable_batcher: bool,
595 experimental_enable_prometheus_native_histogram: bool,
596) -> (Router, TestGuard) {
597 unsafe {
598 std::env::set_var("TZ", "UTC");
599 }
600
601 let instance = setup_standalone_instance(name, store_type).await;
602
603 let sql = "CREATE TABLE phy (ts timestamp time index, val double, host string primary key) engine=metric with ('physical_metric_table' = '')";
605 run_sql(sql, &instance).await;
606 let sql = "CREATE TABLE phy_ns (ts timestamp(0) time index, val double, host string primary key) engine=metric with ('physical_metric_table' = '')";
607 run_sql(sql, &instance).await;
608 let sql = "CREATE TABLE demo (ts timestamp time index, val double, host string primary key) engine=metric with ('on_physical_table' = 'phy')";
610 run_sql(sql, &instance).await;
611 let sql = "CREATE TABLE demo_metrics (ts timestamp time index, val double, idc string primary key) engine=metric with ('on_physical_table' = 'phy')";
612 run_sql(sql, &instance).await;
613 let sql = "CREATE TABLE multi_labels (ts timestamp(0) time index, val double, idc string, env string, host string, primary key (idc, env, host)) engine=metric with ('on_physical_table' = 'phy_ns')";
614 run_sql(sql, &instance).await;
615
616 let sql = "INSERT INTO demo(host, val, ts) VALUES ('host1', 1.1, 0), ('host2', 2.1, 600000)";
618 run_sql(sql, &instance).await;
619 let sql =
620 "INSERT INTO demo_metrics(idc, val, ts) VALUES ('idc1', 1.1, 0), ('idc2', 2.1, 600000)";
621 run_sql(sql, &instance).await;
622 let sql = "INSERT INTO demo_metrics(val, ts) VALUES (1.1, 0)";
624 run_sql(sql, &instance).await;
625
626 let sql = "INSERT INTO multi_labels(idc, env, host, val, ts) VALUES ('idc1', 'dev', 'host1', 1.1, 0), ('idc1', 'dev', 'host2', 2.1, 0), ('idc2', 'dev', 'host1', 1.1, 0), ('idc2', 'test', 'host3', 2.1, 0)";
628 run_sql(sql, &instance).await;
629
630 let sql = "CREATE TABLE phy2 (ts timestamp(9) time index, val double, host string primary key) engine=metric with ('physical_metric_table' = '')";
632 run_sql(sql, &instance).await;
633 let sql = "CREATE TABLE demo_metrics_with_nanos(ts timestamp(9) time index, val double, idc string primary key) engine=metric with ('on_physical_table' = 'phy2')";
634 run_sql(sql, &instance).await;
635 let sql = "INSERT INTO demo_metrics_with_nanos(idc, val, ts) VALUES ('idc1', 1.1, 0)";
636 run_sql(sql, &instance).await;
637
638 let sql = "CREATE TABLE mito (ts timestamp(9) time index, val double, host bigint primary key) engine=mito";
640 run_sql(sql, &instance).await;
641 let sql = "INSERT INTO mito(host, val, ts) VALUES (1, 1.1, 0)";
642 run_sql(sql, &instance).await;
643
644 let http_opts = HttpOptions {
645 addr: format!("127.0.0.1:{}", ports::get_port()),
646 ..Default::default()
647 };
648 let frontend_ref = instance.fe_instance().clone();
649 let pending_rows_batcher = if enable_batcher {
652 PendingRowsBatcher::try_new(
653 frontend_ref.partition_manager().clone(),
654 frontend_ref.node_manager().clone(),
655 frontend_ref.catalog_manager().clone(),
656 frontend_ref.table_flownode_set_cache().clone(),
657 true,
658 frontend_ref.clone(),
659 Duration::from_millis(50),
660 1000,
661 4,
662 64,
663 64,
664 std::num::NonZeroUsize::new(1024).unwrap(),
665 )
666 } else {
667 None
668 };
669 let http_server = HttpServerBuilder::new(http_opts)
670 .with_sql_handler(frontend_ref.clone())
671 .with_logs_handler(instance.fe_instance().clone())
672 .with_prom_handler(
673 frontend_ref.clone(),
674 Some(frontend_ref.clone()),
675 true,
676 PromValidationMode::Strict,
677 experimental_enable_prometheus_native_histogram,
678 pending_rows_batcher,
679 )
680 .with_prometheus_handler(frontend_ref)
681 .with_greptime_config_options(instance.opts.datanode_options().to_toml().unwrap())
682 .build();
683 let app = http_server.build(http_server.make_app()).unwrap();
684 (app, instance.guard)
685}
686
687pub async fn setup_grpc_server(
688 store_type: StorageType,
689 name: &str,
690) -> (GreptimeDbStandalone, Arc<GrpcServer>) {
691 setup_grpc_server_with(store_type, name, None, None, None).await
692}
693
694pub async fn setup_grpc_server_with_user_provider(
695 store_type: StorageType,
696 name: &str,
697 user_provider: Option<UserProviderRef>,
698) -> (GreptimeDbStandalone, Arc<GrpcServer>) {
699 setup_grpc_server_with(store_type, name, user_provider, None, None).await
700}
701
702pub async fn setup_grpc_server_with_auto_create_table_disabled(
705 store_type: StorageType,
706 name: &str,
707) -> (GreptimeDbStandalone, Arc<GrpcServer>) {
708 let instance = GreptimeDbStandaloneBuilder::new(name)
709 .with_default_store_type(store_type)
710 .with_auto_create_table(false)
711 .build()
712 .await;
713 setup_grpc_server_for_instance(instance, None, None, None).await
714}
715
716pub async fn setup_grpc_server_with(
717 store_type: StorageType,
718 name: &str,
719 user_provider: Option<UserProviderRef>,
720 grpc_config: Option<GrpcServerConfig>,
721 memory_limiter: Option<servers::request_memory_limiter::ServerMemoryLimiter>,
722) -> (GreptimeDbStandalone, Arc<GrpcServer>) {
723 let instance = setup_standalone_instance(name, store_type).await;
724 setup_grpc_server_for_instance(instance, user_provider, grpc_config, memory_limiter).await
725}
726
727async fn setup_grpc_server_for_instance(
730 instance: GreptimeDbStandalone,
731 user_provider: Option<UserProviderRef>,
732 grpc_config: Option<GrpcServerConfig>,
733 memory_limiter: Option<servers::request_memory_limiter::ServerMemoryLimiter>,
734) -> (GreptimeDbStandalone, Arc<GrpcServer>) {
735 let runtime: Runtime = RuntimeBuilder::default()
736 .worker_threads(2)
737 .thread_name("grpc-handlers")
738 .build()
739 .unwrap();
740
741 let fe_instance_ref = instance.fe_instance().clone();
742
743 let greptime_request_handler = GreptimeRequestHandler::new(
744 fe_instance_ref.clone(),
745 user_provider.clone(),
746 Some(runtime.clone()),
747 FlightCompression::default(),
748 );
749
750 let flight_handler = Arc::new(greptime_request_handler.clone());
751
752 let grpc_config = grpc_config.unwrap_or_default();
753 let mut grpc_builder = GrpcServerBuilder::new(grpc_config.clone(), runtime);
754
755 if let Some(limiter) = memory_limiter {
756 grpc_builder = grpc_builder.with_memory_limiter(limiter);
757 }
758
759 let grpc_builder = grpc_builder
760 .database_handler(greptime_request_handler)
761 .flight_handler(flight_handler)
762 .prometheus_handler(fe_instance_ref.clone(), user_provider.clone())
763 .otel_arrow_handler(OtelArrowServiceHandler::new(fe_instance_ref, user_provider))
764 .with_tls_config(grpc_config.tls)
765 .unwrap();
766
767 let mut grpc_server = grpc_builder.build();
768
769 let fe_grpc_addr = "127.0.0.1:0".parse::<SocketAddr>().unwrap();
770 grpc_server.start(fe_grpc_addr).await.unwrap();
771
772 (instance, Arc::new(grpc_server))
773}
774
775pub async fn setup_mysql_server(
776 store_type: StorageType,
777 name: &str,
778) -> (TestGuard, Arc<Box<dyn Server>>) {
779 setup_mysql_server_with_user_provider(store_type, name, None).await
780}
781
782pub async fn setup_mysql_server_with_slow_query_threshold(
783 store_type: StorageType,
784 name: &str,
785 slow_query_threshold: std::time::Duration,
786) -> (TestGuard, Arc<Box<dyn Server>>) {
787 let plugins = Plugins::new();
788 let instance = setup_standalone_instance_with_plugins_and_slow_query_threshold(
789 name,
790 store_type,
791 plugins,
792 slow_query_threshold,
793 )
794 .await;
795
796 let runtime = RuntimeBuilder::default()
797 .worker_threads(2)
798 .thread_name("mysql-runtime")
799 .build()
800 .unwrap();
801
802 let fe_mysql_addr = format!("127.0.0.1:{}", ports::get_port());
803
804 let fe_instance_ref = instance.fe_instance().clone();
805 let opts = MysqlOptions {
806 addr: fe_mysql_addr.clone(),
807 ..Default::default()
808 };
809 let mut mysql_server = MysqlServer::create_server(
810 runtime,
811 Arc::new(MysqlSpawnRef::new(fe_instance_ref, None)),
812 Arc::new(MysqlSpawnConfig::new(
813 false,
814 Arc::new(
815 ReloadableTlsServerConfig::try_new(opts.tls.clone())
816 .expect("Failed to load certificates and keys"),
817 ),
818 0,
819 opts.reject_no_database.unwrap_or(false),
820 opts.prepared_stmt_cache_size,
821 )),
822 None,
823 );
824
825 mysql_server
826 .start(fe_mysql_addr.parse::<SocketAddr>().unwrap())
827 .await
828 .unwrap();
829
830 (instance.guard, Arc::new(mysql_server))
831}
832
833pub async fn setup_mysql_server_with_user_provider(
834 store_type: StorageType,
835 name: &str,
836 user_provider: Option<UserProviderRef>,
837) -> (TestGuard, Arc<Box<dyn Server>>) {
838 let plugins = Plugins::new();
839 if let Some(user_provider) = user_provider.clone() {
840 plugins.insert::<UserProviderRef>(user_provider.clone());
841 plugins.insert::<PermissionCheckerRef>(DefaultPermissionChecker::arc());
842 }
843
844 let instance = setup_standalone_instance_with_plugins(name, store_type, plugins).await;
845
846 let runtime = RuntimeBuilder::default()
847 .worker_threads(2)
848 .thread_name("mysql-runtime")
849 .build()
850 .unwrap();
851
852 let fe_mysql_addr = format!("127.0.0.1:{}", ports::get_port());
853
854 let fe_instance_ref = instance.fe_instance().clone();
855 let opts = MysqlOptions {
856 addr: fe_mysql_addr.clone(),
857 ..Default::default()
858 };
859 let mut mysql_server = MysqlServer::create_server(
860 runtime,
861 Arc::new(MysqlSpawnRef::new(fe_instance_ref, user_provider)),
862 Arc::new(MysqlSpawnConfig::new(
863 false,
864 Arc::new(
865 ReloadableTlsServerConfig::try_new(opts.tls.clone())
866 .expect("Failed to load certificates and keys"),
867 ),
868 0,
869 opts.reject_no_database.unwrap_or(false),
870 opts.prepared_stmt_cache_size,
871 )),
872 None,
873 );
874
875 mysql_server
876 .start(fe_mysql_addr.parse::<SocketAddr>().unwrap())
877 .await
878 .unwrap();
879
880 (instance.guard, Arc::new(mysql_server))
881}
882
883pub async fn setup_pg_server(
884 store_type: StorageType,
885 name: &str,
886) -> (TestGuard, Arc<Box<dyn Server>>) {
887 setup_pg_server_with_user_provider(store_type, name, None).await
888}
889
890pub async fn setup_pg_server_with_slow_query_threshold(
891 store_type: StorageType,
892 name: &str,
893 slow_query_threshold: std::time::Duration,
894) -> (TestGuard, Arc<Box<dyn Server>>) {
895 let instance =
896 setup_standalone_instance_with_slow_query_threshold(name, store_type, slow_query_threshold)
897 .await;
898
899 let runtime = RuntimeBuilder::default()
900 .worker_threads(2)
901 .thread_name("pg-runtime")
902 .build()
903 .unwrap();
904
905 let fe_pg_addr = format!("127.0.0.1:{}", ports::get_port());
906
907 let fe_instance_ref = instance.fe_instance().clone();
908 let opts = PostgresOptions {
909 addr: fe_pg_addr.clone(),
910 ..Default::default()
911 };
912 let tls_server_config = Arc::new(
913 ReloadableTlsServerConfig::try_new(opts.tls.clone())
914 .expect("Failed to load certificates and keys"),
915 );
916
917 let mut pg_server = Box::new(PostgresServer::new(
918 fe_instance_ref,
919 opts.tls.should_force_tls(),
920 tls_server_config,
921 0,
922 runtime,
923 None,
924 None,
925 ));
926
927 pg_server
928 .start(fe_pg_addr.parse::<SocketAddr>().unwrap())
929 .await
930 .unwrap();
931
932 (instance.guard, Arc::new(pg_server))
933}
934
935pub async fn setup_pg_server_with_user_provider(
936 store_type: StorageType,
937 name: &str,
938 user_provider: Option<UserProviderRef>,
939) -> (TestGuard, Arc<Box<dyn Server>>) {
940 let instance = setup_standalone_instance(name, store_type).await;
941
942 let runtime = RuntimeBuilder::default()
943 .worker_threads(2)
944 .thread_name("pg-runtime")
945 .build()
946 .unwrap();
947
948 let fe_pg_addr = format!("127.0.0.1:{}", ports::get_port());
949
950 let fe_instance_ref = instance.fe_instance().clone();
951 let opts = PostgresOptions {
952 addr: fe_pg_addr.clone(),
953 ..Default::default()
954 };
955 let tls_server_config = Arc::new(
956 ReloadableTlsServerConfig::try_new(opts.tls.clone())
957 .expect("Failed to load certificates and keys"),
958 );
959
960 let mut pg_server = Box::new(PostgresServer::new(
961 fe_instance_ref,
962 opts.tls.should_force_tls(),
963 tls_server_config,
964 0,
965 runtime,
966 user_provider,
967 None,
968 ));
969
970 pg_server
971 .start(fe_pg_addr.parse::<SocketAddr>().unwrap())
972 .await
973 .unwrap();
974
975 (instance.guard, Arc::new(pg_server))
976}
977
978pub(crate) async fn prepare_another_catalog_and_schema(instance: &Instance) {
979 let catalog_manager = instance
980 .catalog_manager()
981 .as_any()
982 .downcast_ref::<KvBackendCatalogManager>()
983 .unwrap();
984
985 let table_metadata_manager = catalog_manager.table_metadata_manager_ref();
986 prepare_another_catalog_and_schema_with_manager(table_metadata_manager).await;
987}
988
989pub(crate) async fn prepare_another_catalog_and_schema_with_kv_backend(kv_backend: KvBackendRef) {
990 let table_metadata_manager = TableMetadataManager::new(kv_backend);
991 prepare_another_catalog_and_schema_with_manager(&table_metadata_manager).await;
992}
993
994async fn prepare_another_catalog_and_schema_with_manager(
995 table_metadata_manager: &TableMetadataManager,
996) {
997 table_metadata_manager
998 .catalog_manager()
999 .create(CatalogNameKey::new("another_catalog"), true)
1000 .await
1001 .unwrap();
1002 table_metadata_manager
1003 .schema_manager()
1004 .create(
1005 SchemaNameKey::new("another_catalog", "another_schema"),
1006 None,
1007 true,
1008 )
1009 .await
1010 .unwrap();
1011}
1012
1013pub async fn execute_sql(instance: &Arc<Instance>, sql: &str) -> Output {
1014 SqlQueryHandler::do_query(instance.as_ref(), sql, QueryContext::arc())
1015 .await
1016 .remove(0)
1017 .unwrap()
1018}
1019
1020pub async fn try_execute_sql(
1021 instance: &Arc<Instance>,
1022 sql: &str,
1023) -> servers::error::Result<Output> {
1024 SqlQueryHandler::do_query(instance.as_ref(), sql, QueryContext::arc())
1025 .await
1026 .remove(0)
1027}
1028
1029pub async fn execute_sql_and_expect(instance: &Arc<Instance>, sql: &str, expected: &str) {
1030 let output = execute_sql(instance, sql).await;
1031 let output = output.data.pretty_print().await;
1032 assert_eq!(output, expected.trim());
1033}