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