1use std::collections::BTreeMap;
16#[cfg(test)]
17use std::collections::HashMap;
18use std::env;
19use std::fmt::Display;
20use std::net::SocketAddr;
21use std::sync::Arc;
22use std::time::Duration;
23
24use api::v1::Basic;
25use auth::{
26 DefaultPermissionChecker, PermissionCheckerRef, UserProviderRef, user_provider_from_option,
27};
28use axum::Router;
29use catalog::kvbackend::KvBackendCatalogManager;
30use client::{Client, Database};
31use common_base::Plugins;
32use common_catalog::consts::MIN_USER_TABLE_ID;
33use common_config::Configurable;
34use common_event_recorder::EventRecorderOptions;
35#[cfg(test)]
36use common_meta::DatanodeId;
37use common_meta::key::TableMetadataManager;
38use common_meta::key::catalog_name::CatalogNameKey;
39use common_meta::key::schema_name::SchemaNameKey;
40use common_meta::kv_backend::KvBackendRef;
41use common_query::Output;
42use common_runtime::runtime::BuilderBuild;
43use common_runtime::{Builder as RuntimeBuilder, Runtime};
44use common_test_util::ports;
45use common_test_util::temp_dir::{TempDir, create_temp_dir};
46use common_wal::config::DatanodeWalConfig;
47use datanode::config::{DatanodeOptions, StorageConfig};
48#[cfg(test)]
49use datanode::datanode::Datanode;
50use frontend::instance::Instance;
51use frontend::service_config::{MysqlOptions, PostgresOptions};
52#[cfg(test)]
53use meta_srv::metasrv::Metasrv;
54use mito2::engine::MitoEngine;
55use mito2::gc::GcConfig;
56use object_store::config::{
57 AzblobConfig, FileConfig, GcsConfig, ObjectStoreConfig, OssConfig, S3Config,
58};
59use object_store::services::{Azblob, Gcs, Oss, S3};
60use object_store::test_util::TempFolder;
61use object_store::{AzblobConnection, GcsConnection, ObjectStore, OssConnection, S3Connection};
62use servers::batcher::logical_table::LogicalTablePendingRowsBatcher;
63use servers::grpc::builder::GrpcServerBuilder;
64use servers::grpc::greptime_handler::GreptimeRequestHandler;
65use servers::grpc::{FlightCompression, GrpcOptions, GrpcServer, GrpcServerConfig};
66use servers::http::{HttpOptions, HttpServerBuilder};
67use servers::metrics_handler::MetricsHandler;
68use servers::mysql::server::{MysqlServer, MysqlSpawnConfig, MysqlSpawnRef};
69use servers::otel_arrow::OtelArrowServiceHandler;
70use servers::postgres::PostgresServer;
71use servers::prom_remote_write::validation::PromValidationMode;
72use servers::query_handler::sql::SqlQueryHandler;
73use servers::request_memory_limiter::ServerMemoryLimiter;
74use servers::server::Server;
75use servers::tls::ReloadableTlsServerConfig;
76use session::context::QueryContext;
77use store_api::metric_engine_consts::METRIC_METADATA_REGION_GROUP;
78use store_api::region_engine::RegionEngine;
79use store_api::region_request::{RegionFlushRequest, RegionRequest};
80use store_api::storage::RegionId;
81
82use crate::cluster::{GreptimeDbCluster, GreptimeDbClusterBuilder};
83use crate::standalone::{GreptimeDbStandalone, GreptimeDbStandaloneBuilder};
84
85pub type WalSnapshot = BTreeMap<(u64, RegionId), (u64, u64)>;
87
88async fn flush_and_snapshot_region_wal(engine: &MitoEngine) -> WalSnapshot {
91 let mut snapshot = BTreeMap::new();
92 for region in engine.regions() {
93 let id = region.region_id();
94 if id.table_id() < MIN_USER_TABLE_ID || id.region_group() == METRIC_METADATA_REGION_GROUP {
95 continue;
96 }
97 engine
98 .handle_request(id, RegionRequest::Flush(RegionFlushRequest::default()))
99 .await
100 .unwrap();
101 let statistic = engine.region_statistic(id).unwrap();
102 snapshot.insert(
103 (0, id),
104 (
105 region.flushed_sequence(),
106 statistic.manifest.data_flushed_entry_id(),
107 ),
108 );
109 }
110 snapshot
111}
112
113pub fn assert_wal_delta(before: &WalSnapshot, after: &WalSnapshot, skip_wal: bool) {
115 assert_eq!(
116 before.keys().collect::<Vec<_>>(),
117 after.keys().collect::<Vec<_>>(),
118 "warm up table creation before taking the snapshot"
119 );
120 let mut written = 0;
121 for (id, &(flushed_sequence, flushed_entry_id)) in after {
122 let (previous_flushed_sequence, previous_flushed_entry_id) = before[id];
123 if flushed_sequence > previous_flushed_sequence {
124 written += 1;
125 if skip_wal {
126 assert_eq!(
127 flushed_entry_id, previous_flushed_entry_id,
128 "region {id:?} wrote WAL despite the request policy"
129 );
130 } else {
131 assert!(
132 flushed_entry_id > previous_flushed_entry_id,
133 "region {id:?} did not write WAL"
134 );
135 }
136 }
137 }
138 assert!(
139 written > 0,
140 "request must reach a data region, not merely return success"
141 );
142}
143
144pub enum MockInstanceImpl {
146 Standalone(GreptimeDbStandalone),
147 Distributed(GreptimeDbCluster),
148}
149
150impl MockInstanceImpl {
151 #[cfg(test)]
156 pub(crate) fn metasrv(&self) -> &Arc<Metasrv> {
157 match self {
158 Self::Standalone(_) => unreachable!(),
159 Self::Distributed(instance) => &instance.metasrv,
160 }
161 }
162
163 #[cfg(test)]
168 pub(crate) fn datanodes(&self) -> &HashMap<DatanodeId, Datanode> {
169 match self {
170 Self::Standalone(_) => unreachable!(),
171 Self::Distributed(instance) => &instance.datanode_instances,
172 }
173 }
174
175 pub async fn new(name: &str, distributed: bool) -> Self {
177 let name = format!(
178 "{name}_{}",
179 if distributed {
180 "distributed"
181 } else {
182 "standalone"
183 }
184 );
185 if distributed {
186 Self::Distributed(
189 GreptimeDbClusterBuilder::new(&name)
190 .await
191 .with_datanodes(3)
192 .build(false)
193 .await,
194 )
195 } else {
196 Self::Standalone(GreptimeDbStandaloneBuilder::new(&name).build().await)
197 }
198 }
199
200 pub fn frontend(&self) -> Arc<Instance> {
202 match self {
203 Self::Standalone(instance) => instance.fe_instance().clone(),
204 Self::Distributed(cluster) => cluster.fe_instance().clone(),
205 }
206 }
207
208 pub async fn flush_and_snapshot_wal(&self) -> WalSnapshot {
210 match self {
211 Self::Standalone(instance) => {
212 flush_and_snapshot_region_wal(&instance.mito_engine).await
213 }
214 Self::Distributed(cluster) => {
215 let mut result = BTreeMap::new();
216 for (node_id, datanode) in &cluster.datanode_instances {
217 let engine = datanode.region_server().mito_engine().unwrap();
218 result.extend(
219 flush_and_snapshot_region_wal(&engine)
220 .await
221 .into_iter()
222 .map(|((_, region_id), watermarks)| {
223 ((*node_id, region_id), watermarks)
224 }),
225 );
226 }
227 result
228 }
229 }
230 }
231
232 pub async fn shutdown(&mut self) {
234 match self {
235 Self::Standalone(instance) => instance.guard.remove_all().await,
236 Self::Distributed(cluster) => {
237 cluster.metasrv.shutdown().await.unwrap();
238 for datanode in cluster.datanode_instances.values_mut() {
239 datanode.shutdown().await.unwrap();
240 }
241 for guard in &mut cluster.guards {
242 guard.remove_all().await;
243 }
244 }
245 }
246 }
247}
248
249pub const PEER_PLACEHOLDER_ADDR: &str = "127.0.0.1:3001";
250
251#[derive(Debug, Clone, Copy, Eq, PartialEq)]
252pub enum StorageType {
253 S3,
254 S3WithCache,
255 File,
256 Oss,
257 Azblob,
258 Gcs,
259}
260
261impl Display for StorageType {
262 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
263 match self {
264 StorageType::S3 => write!(f, "S3"),
265 StorageType::S3WithCache => write!(f, "S3"),
266 StorageType::File => write!(f, "File"),
267 StorageType::Oss => write!(f, "Oss"),
268 StorageType::Azblob => write!(f, "Azblob"),
269 StorageType::Gcs => write!(f, "Gcs"),
270 }
271 }
272}
273
274impl StorageType {
275 pub fn build_storage_types_based_on_env() -> Vec<StorageType> {
276 let mut storage_types = Vec::with_capacity(4);
277 storage_types.push(StorageType::File);
278 if let Ok(bucket) = env::var("GT_S3_BUCKET")
279 && !bucket.is_empty()
280 {
281 storage_types.push(StorageType::S3);
282 }
283 if env::var("GT_OSS_BUCKET").is_ok() {
284 storage_types.push(StorageType::Oss);
285 }
286 if env::var("GT_AZBLOB_CONTAINER").is_ok() {
287 storage_types.push(StorageType::Azblob);
288 }
289 if env::var("GT_GCS_BUCKET").is_ok() {
290 storage_types.push(StorageType::Gcs);
291 }
292 storage_types
293 }
294
295 pub fn test_on(&self) -> bool {
296 let _ = dotenv::dotenv();
297
298 match self {
299 StorageType::File => true, StorageType::S3 | StorageType::S3WithCache => {
301 if let Ok(b) = env::var("GT_S3_BUCKET") {
302 !b.is_empty()
303 } else {
304 false
305 }
306 }
307 StorageType::Oss => {
308 if let Ok(b) = env::var("GT_OSS_BUCKET") {
309 !b.is_empty()
310 } else {
311 false
312 }
313 }
314 StorageType::Azblob => {
315 if let Ok(b) = env::var("GT_AZBLOB_CONTAINER") {
316 !b.is_empty()
317 } else {
318 false
319 }
320 }
321 StorageType::Gcs => {
322 if let Ok(b) = env::var("GT_GCS_BUCKET") {
323 !b.is_empty()
324 } else {
325 false
326 }
327 }
328 }
329 }
330}
331
332pub fn test_event_recorder_options() -> EventRecorderOptions {
338 EventRecorderOptions {
339 flush_interval: Duration::from_millis(100),
340 ..Default::default()
341 }
342}
343
344fn s3_test_config() -> S3Config {
345 S3Config {
346 connection: S3Connection {
347 root: uuid::Uuid::new_v4().to_string(),
348 access_key_id: env::var("GT_S3_ACCESS_KEY_ID").unwrap().into(),
349 secret_access_key: env::var("GT_S3_ACCESS_KEY").unwrap().into(),
350 bucket: env::var("GT_S3_BUCKET").unwrap(),
351 region: Some(env::var("GT_S3_REGION").unwrap()),
352 endpoint: env::var("GT_S3_ENDPOINT_URL").ok(),
353 ..Default::default()
354 },
355 ..Default::default()
356 }
357}
358
359pub fn get_test_store_config(store_type: &StorageType) -> (ObjectStoreConfig, TempDirGuard) {
360 let _ = dotenv::dotenv();
361
362 match store_type {
363 StorageType::Gcs => {
364 let gcs_config = GcsConfig {
365 connection: GcsConnection {
366 root: uuid::Uuid::new_v4().to_string(),
367 bucket: env::var("GT_GCS_BUCKET").unwrap(),
368 scope: env::var("GT_GCS_SCOPE").unwrap(),
369 credential_path: env::var("GT_GCS_CREDENTIAL_PATH").unwrap().into(),
370 credential: env::var("GT_GCS_CREDENTIAL").unwrap().into(),
371 endpoint: env::var("GT_GCS_ENDPOINT").unwrap_or_default(),
372 },
373 ..Default::default()
374 };
375
376 let builder = Gcs::from(&gcs_config.connection);
377 let config = ObjectStoreConfig::Gcs(gcs_config);
378 let store = ObjectStore::new(builder).unwrap();
379 (config, TempDirGuard::remote(TempFolder::new(&store, "/")))
380 }
381 StorageType::Azblob => {
382 let azblob_config = AzblobConfig {
383 connection: AzblobConnection {
384 root: uuid::Uuid::new_v4().to_string(),
385 container: env::var("GT_AZBLOB_CONTAINER").unwrap(),
386 account_name: env::var("GT_AZBLOB_ACCOUNT_NAME").unwrap().into(),
387 account_key: env::var("GT_AZBLOB_ACCOUNT_KEY").unwrap().into(),
388 endpoint: env::var("GT_AZBLOB_ENDPOINT").unwrap(),
389 ..Default::default()
390 },
391 ..Default::default()
392 };
393
394 let builder = Azblob::from(&azblob_config.connection);
395 let config = ObjectStoreConfig::Azblob(azblob_config);
396 let store = ObjectStore::new(builder).unwrap();
397 (config, TempDirGuard::remote(TempFolder::new(&store, "/")))
398 }
399 StorageType::Oss => {
400 let oss_config = OssConfig {
401 connection: OssConnection {
402 root: uuid::Uuid::new_v4().to_string(),
403 access_key_id: env::var("GT_OSS_ACCESS_KEY_ID").unwrap().into(),
404 access_key_secret: env::var("GT_OSS_ACCESS_KEY").unwrap().into(),
405 bucket: env::var("GT_OSS_BUCKET").unwrap(),
406 endpoint: env::var("GT_OSS_ENDPOINT").unwrap(),
407 },
408 ..Default::default()
409 };
410
411 let builder = Oss::from(&oss_config.connection);
412 let config = ObjectStoreConfig::Oss(oss_config);
413 let store = ObjectStore::new(builder).unwrap();
414 (config, TempDirGuard::remote(TempFolder::new(&store, "/")))
415 }
416 StorageType::S3 | StorageType::S3WithCache => {
417 let mut s3_config = s3_test_config();
418
419 let cache_dir = if *store_type == StorageType::S3WithCache {
423 let dir = create_temp_dir("gt_s3_read_cache");
424 s3_config.cache.cache_path = dir.path().to_string_lossy().to_string();
425 Some(dir)
426 } else {
427 s3_config.cache.enable_read_cache = false;
428 None
429 };
430
431 let builder = S3::from(&s3_config.connection);
432 let config = ObjectStoreConfig::S3(s3_config);
433 let store = ObjectStore::new(builder).unwrap();
434 (
435 config,
436 TempDirGuard {
437 remote: Some(TempFolder::new(&store, "/")),
438 local_cache: cache_dir,
439 },
440 )
441 }
442 StorageType::File => (
443 ObjectStoreConfig::File(FileConfig {}),
444 TempDirGuard::default(),
445 ),
446 }
447}
448
449#[derive(Default)]
450pub struct TempDirGuard {
451 remote: Option<TempFolder>,
453 #[allow(dead_code)]
455 local_cache: Option<TempDir>,
456}
457
458impl TempDirGuard {
459 fn remote(folder: TempFolder) -> Self {
460 Self {
461 remote: Some(folder),
462 local_cache: None,
463 }
464 }
465}
466
467pub struct TestGuard {
468 pub home_guard: FileDirGuard,
469 pub storage_guards: Vec<StorageGuard>,
470}
471
472pub struct FileDirGuard {
473 pub temp_dir: TempDir,
474}
475
476impl FileDirGuard {
477 pub fn new(temp_dir: TempDir) -> Self {
478 Self { temp_dir }
479 }
480}
481
482pub struct StorageGuard(pub TempDirGuard);
483
484impl TestGuard {
485 pub async fn remove_all(&mut self) {
486 for storage_guard in self.storage_guards.iter_mut() {
487 if let Some(guard) = &mut storage_guard.0.remote {
488 guard.remove_all().await.unwrap()
489 }
490 }
491 }
492}
493
494impl Drop for TestGuard {
495 fn drop(&mut self) {
496 let (tx, rx) = std::sync::mpsc::channel();
497
498 let guards = std::mem::take(&mut self.storage_guards);
499 common_runtime::spawn_global(async move {
500 let mut errors = vec![];
501 for guard in guards {
502 if let Some(remote) = guard.0.remote
503 && let Err(e) = remote.remove_all().await
504 {
505 errors.push(e);
506 }
507 }
508 if errors.is_empty() {
509 tx.send(Ok(())).unwrap();
510 } else {
511 tx.send(Err(errors)).unwrap();
512 }
513 });
514 rx.recv().unwrap().unwrap_or_else(|e| panic!("{:?}", e));
515 }
516}
517
518pub fn create_tmp_dir_and_datanode_opts(
519 default_store_type: StorageType,
520 store_provider_types: Vec<StorageType>,
521 name: &str,
522 wal_config: DatanodeWalConfig,
523 gc_config: GcConfig,
524) -> (DatanodeOptions, TestGuard) {
525 let home_tmp_dir = create_temp_dir(&format!("gt_data_{name}"));
526 let home_dir = home_tmp_dir.path().to_str().unwrap().to_string();
527
528 let mut store_providers = Vec::with_capacity(store_provider_types.len());
530 let mut storage_guards = Vec::with_capacity(store_provider_types.len() + 1);
532
533 let (default_store, data_tmp_dir) = get_test_store_config(&default_store_type);
534 storage_guards.push(StorageGuard(data_tmp_dir));
535
536 for store_type in store_provider_types {
537 let (store, data_tmp_dir) = get_test_store_config(&store_type);
538 store_providers.push(store);
539 storage_guards.push(StorageGuard(data_tmp_dir))
540 }
541 let opts = create_datanode_opts(
542 default_store,
543 store_providers,
544 home_dir,
545 wal_config,
546 gc_config,
547 );
548
549 (
550 opts,
551 TestGuard {
552 home_guard: FileDirGuard::new(home_tmp_dir),
553 storage_guards,
554 },
555 )
556}
557
558pub(crate) fn create_datanode_opts(
559 default_store: ObjectStoreConfig,
560 providers: Vec<ObjectStoreConfig>,
561 home_dir: String,
562 wal_config: DatanodeWalConfig,
563 gc_config: GcConfig,
564) -> DatanodeOptions {
565 let region_engine = DatanodeOptions::default()
566 .region_engine
567 .into_iter()
568 .map(|mut v| {
569 if let datanode::config::RegionEngineConfig::Mito(mito_config) = &mut v {
570 mito_config.gc = gc_config.clone();
571 }
572 v
573 })
574 .collect();
575 DatanodeOptions {
576 node_id: Some(0),
577 require_lease_before_startup: true,
578 storage: StorageConfig {
579 data_home: home_dir,
580 copy_root: None,
581 providers,
582 store: default_store,
583 },
584 grpc: GrpcOptions::default()
585 .with_bind_addr(PEER_PLACEHOLDER_ADDR)
586 .with_server_addr(PEER_PLACEHOLDER_ADDR),
587 wal: wal_config,
588 region_engine,
589 ..Default::default()
590 }
591}
592
593pub(crate) async fn create_test_table(instance: &Instance, table_name: &str) {
594 let sql = format!(
595 r#"
596CREATE TABLE IF NOT EXISTS {table_name} (
597 host String NOT NULL PRIMARY KEY,
598 cpu DOUBLE NULL,
599 memory DOUBLE NULL,
600 ts TIMESTAMP NOT NULL TIME INDEX,
601)
602"#
603 );
604
605 let result = instance.do_query(&sql, QueryContext::arc()).await;
606 let _ = result.first().unwrap().as_ref().unwrap();
607}
608
609async fn setup_standalone_instance(
610 test_name: &str,
611 store_type: StorageType,
612) -> GreptimeDbStandalone {
613 GreptimeDbStandaloneBuilder::new(test_name)
614 .with_default_store_type(store_type)
615 .build()
616 .await
617}
618
619async fn setup_standalone_instance_with_slow_query_threshold(
620 test_name: &str,
621 store_type: StorageType,
622 slow_query_threshold: std::time::Duration,
623) -> GreptimeDbStandalone {
624 GreptimeDbStandaloneBuilder::new(test_name)
625 .with_default_store_type(store_type)
626 .with_slow_query_threshold(slow_query_threshold)
627 .build()
628 .await
629}
630
631async fn setup_standalone_instance_with_plugins(
632 test_name: &str,
633 store_type: StorageType,
634 plugins: Plugins,
635) -> GreptimeDbStandalone {
636 GreptimeDbStandaloneBuilder::new(test_name)
637 .with_default_store_type(store_type)
638 .with_plugin(plugins)
639 .build()
640 .await
641}
642
643async fn setup_standalone_instance_with_plugins_and_slow_query_threshold(
644 test_name: &str,
645 store_type: StorageType,
646 plugins: Plugins,
647 slow_query_threshold: std::time::Duration,
648) -> GreptimeDbStandalone {
649 GreptimeDbStandaloneBuilder::new(test_name)
650 .with_default_store_type(store_type)
651 .with_plugin(plugins)
652 .with_slow_query_threshold(slow_query_threshold)
653 .build()
654 .await
655}
656
657pub async fn setup_test_http_app(store_type: StorageType, name: &str) -> (Router, TestGuard) {
658 let instance = setup_standalone_instance(name, store_type).await;
659
660 let http_opts = HttpOptions {
661 addr: format!("127.0.0.1:{}", ports::get_port()),
662 ..Default::default()
663 };
664 let http_server = HttpServerBuilder::new(http_opts)
665 .with_sql_handler(instance.fe_instance().clone())
666 .with_logs_handler(instance.fe_instance().clone())
667 .with_metrics_handler(MetricsHandler)
668 .with_greptime_config_options(instance.opts.datanode_options().to_toml().unwrap())
669 .build();
670 (
671 http_server.build(http_server.make_app()).unwrap(),
672 instance.guard,
673 )
674}
675
676pub async fn setup_test_http_app_with_frontend(
677 store_type: StorageType,
678 name: &str,
679) -> (Router, TestGuard) {
680 setup_test_http_app_with_frontend_and_user_provider(store_type, name, None).await
681}
682
683pub async fn setup_test_http_app_with_frontend_and_slow_query_threshold(
684 store_type: StorageType,
685 name: &str,
686 slow_query_threshold: std::time::Duration,
687) -> (Router, TestGuard) {
688 let instance =
689 setup_standalone_instance_with_slow_query_threshold(name, store_type, slow_query_threshold)
690 .await;
691
692 create_test_table(instance.fe_instance(), "demo").await;
693
694 let http_opts = HttpOptions {
695 addr: format!("127.0.0.1:{}", ports::get_port()),
696 ..Default::default()
697 };
698
699 let http_server = HttpServerBuilder::new(http_opts)
700 .with_sql_handler(instance.fe_instance().clone())
701 .with_log_ingest_handler(instance.fe_instance().clone(), None, None)
702 .with_logs_handler(instance.fe_instance().clone())
703 .with_influxdb_handler(instance.fe_instance().clone())
704 .with_otlp_handler(instance.fe_instance().clone(), true)
705 .with_jaeger_handler(instance.fe_instance().clone())
706 .with_greptime_config_options(instance.opts.to_toml().unwrap())
707 .build();
708
709 let app = http_server.build(http_server.make_app()).unwrap();
710 (app, instance.guard)
711}
712
713pub async fn setup_test_http_app_with_frontend_and_user_provider(
714 store_type: StorageType,
715 name: &str,
716 user_provider: Option<UserProviderRef>,
717) -> (Router, TestGuard) {
718 setup_test_http_app_with_frontend_and_custom_options(
719 store_type,
720 name,
721 user_provider,
722 None,
723 None,
724 )
725 .await
726}
727
728pub async fn setup_test_http_app_with_frontend_and_custom_options(
729 store_type: StorageType,
730 name: &str,
731 user_provider: Option<UserProviderRef>,
732 http_opts: Option<HttpOptions>,
733 memory_limiter: Option<ServerMemoryLimiter>,
734) -> (Router, TestGuard) {
735 let plugins = Plugins::new();
736 if let Some(user_provider) = user_provider.clone() {
737 plugins.insert::<UserProviderRef>(user_provider.clone());
738 plugins.insert::<PermissionCheckerRef>(DefaultPermissionChecker::arc());
739 }
740
741 let instance = setup_standalone_instance_with_plugins(name, store_type, plugins).await;
742
743 create_test_table(instance.fe_instance(), "demo").await;
744
745 let http_opts = http_opts.unwrap_or_else(|| HttpOptions {
746 addr: format!("127.0.0.1:{}", ports::get_port()),
747 ..Default::default()
748 });
749
750 let mut http_server = HttpServerBuilder::new(http_opts)
751 .with_sql_handler(instance.fe_instance().clone())
752 .with_log_ingest_handler(instance.fe_instance().clone(), None, None)
753 .with_logs_handler(instance.fe_instance().clone())
754 .with_influxdb_handler(instance.fe_instance().clone())
755 .with_otlp_handler(instance.fe_instance().clone(), true)
756 .with_prometheus_handler(instance.fe_instance().clone())
757 .with_jaeger_handler(instance.fe_instance().clone())
758 .with_dashboard_handler(instance.fe_instance().clone())
759 .with_greptime_config_options(instance.opts.to_toml().unwrap());
760
761 if let Some(user_provider) = user_provider {
762 http_server = http_server.with_user_provider(user_provider);
763 }
764
765 if let Some(limiter) = memory_limiter {
766 http_server = http_server.with_memory_limiter(limiter);
767 }
768
769 let http_server = http_server.build();
770
771 let app = http_server.build(http_server.make_app()).unwrap();
772 (app, instance.guard)
773}
774
775async fn run_sql(sql: &str, instance: &GreptimeDbStandalone) {
776 let result = instance
777 .fe_instance()
778 .do_query(sql, QueryContext::arc())
779 .await;
780 let _ = result.first().unwrap().as_ref().unwrap();
781}
782
783pub async fn setup_test_prom_app_with_frontend(
784 store_type: StorageType,
785 name: &str,
786) -> (Router, TestGuard) {
787 setup_test_prom_app_with_frontend_inner(store_type, name, false).await
788}
789
790pub async fn setup_test_prom_app_with_frontend_batched(
794 store_type: StorageType,
795 name: &str,
796) -> (Router, TestGuard) {
797 setup_test_prom_app_with_frontend_inner(store_type, name, true).await
798}
799
800async fn setup_test_prom_app_with_frontend_inner(
801 store_type: StorageType,
802 name: &str,
803 enable_batcher: bool,
804) -> (Router, TestGuard) {
805 unsafe {
806 std::env::set_var("TZ", "UTC");
807 }
808
809 let instance = setup_standalone_instance(name, store_type).await;
810
811 let sql = "CREATE TABLE phy (ts timestamp time index, val double, host string primary key) engine=metric with ('physical_metric_table' = '')";
813 run_sql(sql, &instance).await;
814 let sql = "CREATE TABLE phy_ns (ts timestamp(0) time index, val double, host string primary key) engine=metric with ('physical_metric_table' = '')";
815 run_sql(sql, &instance).await;
816 let sql = "CREATE TABLE demo (ts timestamp time index, val double, host string primary key) engine=metric with ('on_physical_table' = 'phy')";
818 run_sql(sql, &instance).await;
819 let sql = "CREATE TABLE demo_metrics (ts timestamp time index, val double, idc string primary key) engine=metric with ('on_physical_table' = 'phy')";
820 run_sql(sql, &instance).await;
821 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')";
822 run_sql(sql, &instance).await;
823
824 let sql = "INSERT INTO demo(host, val, ts) VALUES ('host1', 1.1, 0), ('host2', 2.1, 600000)";
826 run_sql(sql, &instance).await;
827 let sql =
828 "INSERT INTO demo_metrics(idc, val, ts) VALUES ('idc1', 1.1, 0), ('idc2', 2.1, 600000)";
829 run_sql(sql, &instance).await;
830 let sql = "INSERT INTO demo_metrics(val, ts) VALUES (1.1, 0)";
832 run_sql(sql, &instance).await;
833
834 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)";
836 run_sql(sql, &instance).await;
837
838 let sql = "CREATE TABLE phy2 (ts timestamp(9) time index, val double, host string primary key) engine=metric with ('physical_metric_table' = '')";
840 run_sql(sql, &instance).await;
841 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')";
842 run_sql(sql, &instance).await;
843 let sql = "INSERT INTO demo_metrics_with_nanos(idc, val, ts) VALUES ('idc1', 1.1, 0)";
844 run_sql(sql, &instance).await;
845
846 let sql = "CREATE TABLE mito (ts timestamp(9) time index, val double, host bigint primary key) engine=mito";
848 run_sql(sql, &instance).await;
849 let sql = "INSERT INTO mito(host, val, ts) VALUES (1, 1.1, 0)";
850 run_sql(sql, &instance).await;
851
852 let http_server = build_test_prom_server(instance.fe_instance().clone(), enable_batcher)
853 .with_greptime_config_options(instance.opts.datanode_options().to_toml().unwrap())
854 .build();
855 let app = http_server.build(http_server.make_app()).unwrap();
856 (app, instance.guard)
857}
858
859pub fn build_test_prom_server(
861 frontend_ref: Arc<Instance>,
862 enable_batcher: bool,
863) -> HttpServerBuilder {
864 let http_opts = HttpOptions {
865 addr: format!("127.0.0.1:{}", ports::get_port()),
866 ..Default::default()
867 };
868 let pending_rows_batcher = if enable_batcher {
871 LogicalTablePendingRowsBatcher::try_new(
872 frontend_ref.partition_manager().clone(),
873 frontend_ref.node_manager().clone(),
874 frontend_ref.catalog_manager().clone(),
875 frontend_ref.table_flownode_set_cache().clone(),
876 true,
877 frontend_ref.clone(),
878 Duration::from_millis(50),
879 1000,
880 4,
881 64,
882 64,
883 std::num::NonZeroUsize::new(1024).unwrap(),
884 )
885 } else {
886 None
887 };
888 assert_eq!(pending_rows_batcher.is_some(), enable_batcher);
889 HttpServerBuilder::new(http_opts)
890 .with_sql_handler(frontend_ref.clone())
891 .with_logs_handler(frontend_ref.clone())
892 .with_prom_handler(
893 frontend_ref.clone(),
894 Some(frontend_ref.clone()),
895 true,
896 PromValidationMode::Strict,
897 pending_rows_batcher,
898 )
899 .with_prometheus_handler(frontend_ref)
900}
901
902pub async fn setup_grpc_server(
903 store_type: StorageType,
904 name: &str,
905) -> (GreptimeDbStandalone, Arc<GrpcServer>) {
906 setup_grpc_server_with(store_type, name, None, None, None).await
907}
908
909pub async fn setup_grpc_server_with_user_provider(
910 store_type: StorageType,
911 name: &str,
912 user_provider: Option<UserProviderRef>,
913) -> (GreptimeDbStandalone, Arc<GrpcServer>) {
914 setup_grpc_server_with(store_type, name, user_provider, None, None).await
915}
916
917pub async fn setup_grpc_server_with_auto_create_table_disabled(
920 store_type: StorageType,
921 name: &str,
922) -> (GreptimeDbStandalone, Arc<GrpcServer>) {
923 let instance = GreptimeDbStandaloneBuilder::new(name)
924 .with_default_store_type(store_type)
925 .with_auto_create_table(false)
926 .build()
927 .await;
928 setup_grpc_server_for_instance(instance, None, None, None).await
929}
930
931pub async fn setup_grpc_server_with(
932 store_type: StorageType,
933 name: &str,
934 user_provider: Option<UserProviderRef>,
935 grpc_config: Option<GrpcServerConfig>,
936 memory_limiter: Option<servers::request_memory_limiter::ServerMemoryLimiter>,
937) -> (GreptimeDbStandalone, Arc<GrpcServer>) {
938 let instance = setup_standalone_instance(name, store_type).await;
939 setup_grpc_server_for_instance(instance, user_provider, grpc_config, memory_limiter).await
940}
941
942async fn setup_grpc_server_for_instance(
945 instance: GreptimeDbStandalone,
946 user_provider: Option<UserProviderRef>,
947 grpc_config: Option<GrpcServerConfig>,
948 memory_limiter: Option<servers::request_memory_limiter::ServerMemoryLimiter>,
949) -> (GreptimeDbStandalone, Arc<GrpcServer>) {
950 let grpc_server = setup_grpc_server_for_frontend_instance_with(
951 instance.fe_instance().clone(),
952 user_provider,
953 grpc_config,
954 memory_limiter,
955 )
956 .await;
957 (instance, grpc_server)
958}
959
960pub async fn setup_grpc_server_for_frontend_instance(
962 instance: Arc<Instance>,
963 user_provider: Option<UserProviderRef>,
964) -> Arc<GrpcServer> {
965 setup_grpc_server_for_frontend_instance_with(instance, user_provider, None, None).await
966}
967
968pub async fn setup_authenticated_grpc_database(
971 instance: Arc<Instance>,
972 username: &str,
973 password: &str,
974) -> (Database, Arc<GrpcServer>) {
975 let user_provider =
976 user_provider_from_option(&format!("static_user_provider:cmd:{username}={password}"))
977 .unwrap();
978 let grpc_server = setup_grpc_server_for_frontend_instance(instance, Some(user_provider)).await;
979 let grpc_addr = grpc_server.bind_addr().unwrap().to_string();
980 let mut database =
981 Database::new_with_dbname("greptime-public", Client::with_urls(vec![grpc_addr]));
982 database.set_auth(api::v1::auth_header::AuthScheme::Basic(Basic {
983 username: username.to_string(),
984 password: password.to_string(),
985 }));
986 (database, grpc_server)
987}
988
989async fn setup_grpc_server_for_frontend_instance_with(
990 fe_instance_ref: Arc<Instance>,
991 user_provider: Option<UserProviderRef>,
992 grpc_config: Option<GrpcServerConfig>,
993 memory_limiter: Option<servers::request_memory_limiter::ServerMemoryLimiter>,
994) -> Arc<GrpcServer> {
995 let runtime: Runtime = RuntimeBuilder::default()
996 .worker_threads(2)
997 .thread_name("grpc-handlers")
998 .build()
999 .unwrap();
1000
1001 let greptime_request_handler = GreptimeRequestHandler::new(
1002 fe_instance_ref.clone(),
1003 user_provider.clone(),
1004 Some(runtime.clone()),
1005 FlightCompression::default(),
1006 );
1007
1008 let flight_handler = Arc::new(greptime_request_handler.clone());
1009
1010 let grpc_config = grpc_config.unwrap_or_default();
1011 let mut grpc_builder = GrpcServerBuilder::new(grpc_config.clone(), runtime);
1012
1013 if let Some(limiter) = memory_limiter {
1014 grpc_builder = grpc_builder.with_memory_limiter(limiter);
1015 }
1016
1017 let grpc_builder = grpc_builder
1018 .database_handler(greptime_request_handler)
1019 .flight_handler(flight_handler)
1020 .prometheus_handler(fe_instance_ref.clone(), user_provider.clone())
1021 .otel_arrow_handler(OtelArrowServiceHandler::new(fe_instance_ref, user_provider))
1022 .with_tls_config(grpc_config.tls)
1023 .unwrap();
1024
1025 let mut grpc_server = grpc_builder.build();
1026
1027 let fe_grpc_addr = "127.0.0.1:0".parse::<SocketAddr>().unwrap();
1028 grpc_server.start(fe_grpc_addr).await.unwrap();
1029
1030 Arc::new(grpc_server)
1031}
1032
1033pub async fn setup_mysql_server(
1034 store_type: StorageType,
1035 name: &str,
1036) -> (TestGuard, Arc<Box<dyn Server>>) {
1037 setup_mysql_server_with_user_provider(store_type, name, None).await
1038}
1039
1040pub async fn setup_mysql_server_with_slow_query_threshold(
1041 store_type: StorageType,
1042 name: &str,
1043 slow_query_threshold: std::time::Duration,
1044) -> (TestGuard, Arc<Box<dyn Server>>) {
1045 let plugins = Plugins::new();
1046 let instance = setup_standalone_instance_with_plugins_and_slow_query_threshold(
1047 name,
1048 store_type,
1049 plugins,
1050 slow_query_threshold,
1051 )
1052 .await;
1053
1054 let runtime = RuntimeBuilder::default()
1055 .worker_threads(2)
1056 .thread_name("mysql-runtime")
1057 .build()
1058 .unwrap();
1059
1060 let fe_mysql_addr = format!("127.0.0.1:{}", ports::get_port());
1061
1062 let fe_instance_ref = instance.fe_instance().clone();
1063 let opts = MysqlOptions {
1064 addr: fe_mysql_addr.clone(),
1065 ..Default::default()
1066 };
1067 let mut mysql_server = MysqlServer::create_server(
1068 runtime,
1069 Arc::new(MysqlSpawnRef::new(fe_instance_ref, None)),
1070 Arc::new(MysqlSpawnConfig::new(
1071 false,
1072 Arc::new(
1073 ReloadableTlsServerConfig::try_new(opts.tls.clone())
1074 .expect("Failed to load certificates and keys"),
1075 ),
1076 0,
1077 opts.reject_no_database.unwrap_or(false),
1078 opts.prepared_stmt_cache_size,
1079 )),
1080 None,
1081 );
1082
1083 mysql_server
1084 .start(fe_mysql_addr.parse::<SocketAddr>().unwrap())
1085 .await
1086 .unwrap();
1087
1088 (instance.guard, Arc::new(mysql_server))
1089}
1090
1091pub async fn setup_mysql_server_with_user_provider(
1092 store_type: StorageType,
1093 name: &str,
1094 user_provider: Option<UserProviderRef>,
1095) -> (TestGuard, Arc<Box<dyn Server>>) {
1096 let plugins = Plugins::new();
1097 if let Some(user_provider) = user_provider.clone() {
1098 plugins.insert::<UserProviderRef>(user_provider.clone());
1099 plugins.insert::<PermissionCheckerRef>(DefaultPermissionChecker::arc());
1100 }
1101
1102 let instance = setup_standalone_instance_with_plugins(name, store_type, plugins).await;
1103
1104 let runtime = RuntimeBuilder::default()
1105 .worker_threads(2)
1106 .thread_name("mysql-runtime")
1107 .build()
1108 .unwrap();
1109
1110 let fe_mysql_addr = format!("127.0.0.1:{}", ports::get_port());
1111
1112 let fe_instance_ref = instance.fe_instance().clone();
1113 let opts = MysqlOptions {
1114 addr: fe_mysql_addr.clone(),
1115 ..Default::default()
1116 };
1117 let mut mysql_server = MysqlServer::create_server(
1118 runtime,
1119 Arc::new(MysqlSpawnRef::new(fe_instance_ref, user_provider)),
1120 Arc::new(MysqlSpawnConfig::new(
1121 false,
1122 Arc::new(
1123 ReloadableTlsServerConfig::try_new(opts.tls.clone())
1124 .expect("Failed to load certificates and keys"),
1125 ),
1126 0,
1127 opts.reject_no_database.unwrap_or(false),
1128 opts.prepared_stmt_cache_size,
1129 )),
1130 None,
1131 );
1132
1133 mysql_server
1134 .start(fe_mysql_addr.parse::<SocketAddr>().unwrap())
1135 .await
1136 .unwrap();
1137
1138 (instance.guard, Arc::new(mysql_server))
1139}
1140
1141pub async fn setup_pg_server(
1142 store_type: StorageType,
1143 name: &str,
1144) -> (TestGuard, Arc<Box<dyn Server>>) {
1145 setup_pg_server_with_user_provider(store_type, name, None).await
1146}
1147
1148pub async fn setup_pg_server_with_slow_query_threshold(
1149 store_type: StorageType,
1150 name: &str,
1151 slow_query_threshold: std::time::Duration,
1152) -> (TestGuard, Arc<Box<dyn Server>>) {
1153 let instance =
1154 setup_standalone_instance_with_slow_query_threshold(name, store_type, slow_query_threshold)
1155 .await;
1156
1157 let runtime = RuntimeBuilder::default()
1158 .worker_threads(2)
1159 .thread_name("pg-runtime")
1160 .build()
1161 .unwrap();
1162
1163 let fe_pg_addr = format!("127.0.0.1:{}", ports::get_port());
1164
1165 let fe_instance_ref = instance.fe_instance().clone();
1166 let opts = PostgresOptions {
1167 addr: fe_pg_addr.clone(),
1168 ..Default::default()
1169 };
1170 let tls_server_config = Arc::new(
1171 ReloadableTlsServerConfig::try_new(opts.tls.clone())
1172 .expect("Failed to load certificates and keys"),
1173 );
1174
1175 let mut pg_server = Box::new(PostgresServer::new(
1176 fe_instance_ref,
1177 opts.tls.should_force_tls(),
1178 tls_server_config,
1179 0,
1180 runtime,
1181 None,
1182 None,
1183 ));
1184
1185 pg_server
1186 .start(fe_pg_addr.parse::<SocketAddr>().unwrap())
1187 .await
1188 .unwrap();
1189
1190 (instance.guard, Arc::new(pg_server))
1191}
1192
1193pub async fn setup_pg_server_with_user_provider(
1194 store_type: StorageType,
1195 name: &str,
1196 user_provider: Option<UserProviderRef>,
1197) -> (TestGuard, Arc<Box<dyn Server>>) {
1198 let instance = setup_standalone_instance(name, store_type).await;
1199
1200 let runtime = RuntimeBuilder::default()
1201 .worker_threads(2)
1202 .thread_name("pg-runtime")
1203 .build()
1204 .unwrap();
1205
1206 let fe_pg_addr = format!("127.0.0.1:{}", ports::get_port());
1207
1208 let fe_instance_ref = instance.fe_instance().clone();
1209 let opts = PostgresOptions {
1210 addr: fe_pg_addr.clone(),
1211 ..Default::default()
1212 };
1213 let tls_server_config = Arc::new(
1214 ReloadableTlsServerConfig::try_new(opts.tls.clone())
1215 .expect("Failed to load certificates and keys"),
1216 );
1217
1218 let mut pg_server = Box::new(PostgresServer::new(
1219 fe_instance_ref,
1220 opts.tls.should_force_tls(),
1221 tls_server_config,
1222 0,
1223 runtime,
1224 user_provider,
1225 None,
1226 ));
1227
1228 pg_server
1229 .start(fe_pg_addr.parse::<SocketAddr>().unwrap())
1230 .await
1231 .unwrap();
1232
1233 (instance.guard, Arc::new(pg_server))
1234}
1235
1236pub async fn setup_pg_server_with_prom_native_histogram(
1241 store_type: StorageType,
1242 name: &str,
1243) -> (TestGuard, Router, Arc<Box<dyn Server>>) {
1244 unsafe {
1245 std::env::set_var("TZ", "UTC");
1246 }
1247
1248 let instance = setup_standalone_instance(name, store_type).await;
1249
1250 let http_server = build_test_prom_server(instance.fe_instance().clone(), false)
1252 .with_greptime_config_options(instance.opts.datanode_options().to_toml().unwrap())
1253 .build();
1254 let app = http_server.build(http_server.make_app()).unwrap();
1255
1256 let runtime = RuntimeBuilder::default()
1258 .worker_threads(2)
1259 .thread_name("pg-runtime")
1260 .build()
1261 .unwrap();
1262
1263 let fe_pg_addr = format!("127.0.0.1:{}", ports::get_port());
1264 let opts = PostgresOptions {
1265 addr: fe_pg_addr.clone(),
1266 ..Default::default()
1267 };
1268 let tls_server_config = Arc::new(
1269 ReloadableTlsServerConfig::try_new(opts.tls.clone())
1270 .expect("Failed to load certificates and keys"),
1271 );
1272
1273 let mut pg_server = Box::new(PostgresServer::new(
1274 instance.fe_instance().clone(),
1275 opts.tls.should_force_tls(),
1276 tls_server_config,
1277 0,
1278 runtime,
1279 None,
1280 None,
1281 ));
1282
1283 pg_server
1284 .start(fe_pg_addr.parse::<SocketAddr>().unwrap())
1285 .await
1286 .unwrap();
1287
1288 (instance.guard, app, Arc::new(pg_server))
1289}
1290
1291pub(crate) async fn prepare_another_catalog_and_schema(instance: &Instance) {
1292 let catalog_manager = instance
1293 .catalog_manager()
1294 .as_any()
1295 .downcast_ref::<KvBackendCatalogManager>()
1296 .unwrap();
1297
1298 let table_metadata_manager = catalog_manager.table_metadata_manager_ref();
1299 prepare_another_catalog_and_schema_with_manager(table_metadata_manager).await;
1300}
1301
1302pub(crate) async fn prepare_another_catalog_and_schema_with_kv_backend(kv_backend: KvBackendRef) {
1303 let table_metadata_manager = TableMetadataManager::new(kv_backend);
1304 prepare_another_catalog_and_schema_with_manager(&table_metadata_manager).await;
1305}
1306
1307async fn prepare_another_catalog_and_schema_with_manager(
1308 table_metadata_manager: &TableMetadataManager,
1309) {
1310 table_metadata_manager
1311 .catalog_manager()
1312 .create(CatalogNameKey::new("another_catalog"), true)
1313 .await
1314 .unwrap();
1315 table_metadata_manager
1316 .schema_manager()
1317 .create(
1318 SchemaNameKey::new("another_catalog", "another_schema"),
1319 None,
1320 true,
1321 )
1322 .await
1323 .unwrap();
1324}
1325
1326pub async fn execute_sql(instance: &Arc<Instance>, sql: &str) -> Output {
1327 SqlQueryHandler::do_query(instance.as_ref(), sql, QueryContext::arc())
1328 .await
1329 .remove(0)
1330 .unwrap()
1331}
1332
1333pub async fn try_execute_sql(
1334 instance: &Arc<Instance>,
1335 sql: &str,
1336) -> servers::error::Result<Output> {
1337 SqlQueryHandler::do_query(instance.as_ref(), sql, QueryContext::arc())
1338 .await
1339 .remove(0)
1340}
1341
1342pub async fn execute_sql_and_expect(instance: &Arc<Instance>, sql: &str, expected: &str) {
1343 let output = execute_sql(instance, sql).await;
1344 let output = output.data.pretty_print().await;
1345 assert_eq!(output, expected.trim());
1346}