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 = Database::new_with_dbname(
981 "greptime-public",
982 Client::with_query_and_control_managers(
983 Default::default(),
984 Default::default(),
985 vec![grpc_addr],
986 ),
987 );
988 database.set_auth(api::v1::auth_header::AuthScheme::Basic(Basic {
989 username: username.to_string(),
990 password: password.to_string(),
991 }));
992 (database, grpc_server)
993}
994
995async fn setup_grpc_server_for_frontend_instance_with(
996 fe_instance_ref: Arc<Instance>,
997 user_provider: Option<UserProviderRef>,
998 grpc_config: Option<GrpcServerConfig>,
999 memory_limiter: Option<servers::request_memory_limiter::ServerMemoryLimiter>,
1000) -> Arc<GrpcServer> {
1001 let runtime: Runtime = RuntimeBuilder::default()
1002 .worker_threads(2)
1003 .thread_name("grpc-handlers")
1004 .build()
1005 .unwrap();
1006
1007 let greptime_request_handler = GreptimeRequestHandler::new(
1008 fe_instance_ref.clone(),
1009 user_provider.clone(),
1010 Some(runtime.clone()),
1011 FlightCompression::default(),
1012 );
1013
1014 let flight_handler = Arc::new(greptime_request_handler.clone());
1015
1016 let grpc_config = grpc_config.unwrap_or_default();
1017 let mut grpc_builder = GrpcServerBuilder::new(grpc_config.clone(), runtime);
1018
1019 if let Some(limiter) = memory_limiter {
1020 grpc_builder = grpc_builder.with_memory_limiter(limiter);
1021 }
1022
1023 let grpc_builder = grpc_builder
1024 .database_handler(greptime_request_handler)
1025 .flight_handler(flight_handler)
1026 .prometheus_handler(fe_instance_ref.clone(), user_provider.clone())
1027 .otel_arrow_handler(OtelArrowServiceHandler::new(fe_instance_ref, user_provider))
1028 .with_tls_config(grpc_config.tls)
1029 .unwrap();
1030
1031 let mut grpc_server = grpc_builder.build();
1032
1033 let fe_grpc_addr = "127.0.0.1:0".parse::<SocketAddr>().unwrap();
1034 grpc_server.start(fe_grpc_addr).await.unwrap();
1035
1036 Arc::new(grpc_server)
1037}
1038
1039pub async fn setup_mysql_server(
1040 store_type: StorageType,
1041 name: &str,
1042) -> (TestGuard, Arc<Box<dyn Server>>) {
1043 setup_mysql_server_with_user_provider(store_type, name, None).await
1044}
1045
1046pub async fn setup_mysql_server_with_slow_query_threshold(
1047 store_type: StorageType,
1048 name: &str,
1049 slow_query_threshold: std::time::Duration,
1050) -> (TestGuard, Arc<Box<dyn Server>>) {
1051 let plugins = Plugins::new();
1052 let instance = setup_standalone_instance_with_plugins_and_slow_query_threshold(
1053 name,
1054 store_type,
1055 plugins,
1056 slow_query_threshold,
1057 )
1058 .await;
1059
1060 let runtime = RuntimeBuilder::default()
1061 .worker_threads(2)
1062 .thread_name("mysql-runtime")
1063 .build()
1064 .unwrap();
1065
1066 let fe_mysql_addr = format!("127.0.0.1:{}", ports::get_port());
1067
1068 let fe_instance_ref = instance.fe_instance().clone();
1069 let opts = MysqlOptions {
1070 addr: fe_mysql_addr.clone(),
1071 ..Default::default()
1072 };
1073 let mut mysql_server = MysqlServer::create_server(
1074 runtime,
1075 Arc::new(MysqlSpawnRef::new(fe_instance_ref, None)),
1076 Arc::new(MysqlSpawnConfig::new(
1077 false,
1078 Arc::new(
1079 ReloadableTlsServerConfig::try_new(opts.tls.clone())
1080 .expect("Failed to load certificates and keys"),
1081 ),
1082 0,
1083 opts.reject_no_database.unwrap_or(false),
1084 opts.prepared_stmt_cache_size,
1085 )),
1086 None,
1087 );
1088
1089 mysql_server
1090 .start(fe_mysql_addr.parse::<SocketAddr>().unwrap())
1091 .await
1092 .unwrap();
1093
1094 (instance.guard, Arc::new(mysql_server))
1095}
1096
1097pub async fn setup_mysql_server_with_user_provider(
1098 store_type: StorageType,
1099 name: &str,
1100 user_provider: Option<UserProviderRef>,
1101) -> (TestGuard, Arc<Box<dyn Server>>) {
1102 let plugins = Plugins::new();
1103 if let Some(user_provider) = user_provider.clone() {
1104 plugins.insert::<UserProviderRef>(user_provider.clone());
1105 plugins.insert::<PermissionCheckerRef>(DefaultPermissionChecker::arc());
1106 }
1107
1108 let instance = setup_standalone_instance_with_plugins(name, store_type, plugins).await;
1109
1110 let runtime = RuntimeBuilder::default()
1111 .worker_threads(2)
1112 .thread_name("mysql-runtime")
1113 .build()
1114 .unwrap();
1115
1116 let fe_mysql_addr = format!("127.0.0.1:{}", ports::get_port());
1117
1118 let fe_instance_ref = instance.fe_instance().clone();
1119 let opts = MysqlOptions {
1120 addr: fe_mysql_addr.clone(),
1121 ..Default::default()
1122 };
1123 let mut mysql_server = MysqlServer::create_server(
1124 runtime,
1125 Arc::new(MysqlSpawnRef::new(fe_instance_ref, user_provider)),
1126 Arc::new(MysqlSpawnConfig::new(
1127 false,
1128 Arc::new(
1129 ReloadableTlsServerConfig::try_new(opts.tls.clone())
1130 .expect("Failed to load certificates and keys"),
1131 ),
1132 0,
1133 opts.reject_no_database.unwrap_or(false),
1134 opts.prepared_stmt_cache_size,
1135 )),
1136 None,
1137 );
1138
1139 mysql_server
1140 .start(fe_mysql_addr.parse::<SocketAddr>().unwrap())
1141 .await
1142 .unwrap();
1143
1144 (instance.guard, Arc::new(mysql_server))
1145}
1146
1147pub async fn setup_pg_server(
1148 store_type: StorageType,
1149 name: &str,
1150) -> (TestGuard, Arc<Box<dyn Server>>) {
1151 setup_pg_server_with_user_provider(store_type, name, None).await
1152}
1153
1154pub async fn setup_pg_server_with_slow_query_threshold(
1155 store_type: StorageType,
1156 name: &str,
1157 slow_query_threshold: std::time::Duration,
1158) -> (TestGuard, Arc<Box<dyn Server>>) {
1159 let instance =
1160 setup_standalone_instance_with_slow_query_threshold(name, store_type, slow_query_threshold)
1161 .await;
1162
1163 let runtime = RuntimeBuilder::default()
1164 .worker_threads(2)
1165 .thread_name("pg-runtime")
1166 .build()
1167 .unwrap();
1168
1169 let fe_pg_addr = format!("127.0.0.1:{}", ports::get_port());
1170
1171 let fe_instance_ref = instance.fe_instance().clone();
1172 let opts = PostgresOptions {
1173 addr: fe_pg_addr.clone(),
1174 ..Default::default()
1175 };
1176 let tls_server_config = Arc::new(
1177 ReloadableTlsServerConfig::try_new(opts.tls.clone())
1178 .expect("Failed to load certificates and keys"),
1179 );
1180
1181 let mut pg_server = Box::new(PostgresServer::new(
1182 fe_instance_ref,
1183 opts.tls.should_force_tls(),
1184 tls_server_config,
1185 0,
1186 runtime,
1187 None,
1188 None,
1189 ));
1190
1191 pg_server
1192 .start(fe_pg_addr.parse::<SocketAddr>().unwrap())
1193 .await
1194 .unwrap();
1195
1196 (instance.guard, Arc::new(pg_server))
1197}
1198
1199pub async fn setup_pg_server_with_user_provider(
1200 store_type: StorageType,
1201 name: &str,
1202 user_provider: Option<UserProviderRef>,
1203) -> (TestGuard, Arc<Box<dyn Server>>) {
1204 let instance = setup_standalone_instance(name, store_type).await;
1205
1206 let runtime = RuntimeBuilder::default()
1207 .worker_threads(2)
1208 .thread_name("pg-runtime")
1209 .build()
1210 .unwrap();
1211
1212 let fe_pg_addr = format!("127.0.0.1:{}", ports::get_port());
1213
1214 let fe_instance_ref = instance.fe_instance().clone();
1215 let opts = PostgresOptions {
1216 addr: fe_pg_addr.clone(),
1217 ..Default::default()
1218 };
1219 let tls_server_config = Arc::new(
1220 ReloadableTlsServerConfig::try_new(opts.tls.clone())
1221 .expect("Failed to load certificates and keys"),
1222 );
1223
1224 let mut pg_server = Box::new(PostgresServer::new(
1225 fe_instance_ref,
1226 opts.tls.should_force_tls(),
1227 tls_server_config,
1228 0,
1229 runtime,
1230 user_provider,
1231 None,
1232 ));
1233
1234 pg_server
1235 .start(fe_pg_addr.parse::<SocketAddr>().unwrap())
1236 .await
1237 .unwrap();
1238
1239 (instance.guard, Arc::new(pg_server))
1240}
1241
1242pub async fn setup_pg_server_with_prom_native_histogram(
1247 store_type: StorageType,
1248 name: &str,
1249) -> (TestGuard, Router, Arc<Box<dyn Server>>) {
1250 unsafe {
1251 std::env::set_var("TZ", "UTC");
1252 }
1253
1254 let instance = setup_standalone_instance(name, store_type).await;
1255
1256 let http_server = build_test_prom_server(instance.fe_instance().clone(), false)
1258 .with_greptime_config_options(instance.opts.datanode_options().to_toml().unwrap())
1259 .build();
1260 let app = http_server.build(http_server.make_app()).unwrap();
1261
1262 let runtime = RuntimeBuilder::default()
1264 .worker_threads(2)
1265 .thread_name("pg-runtime")
1266 .build()
1267 .unwrap();
1268
1269 let fe_pg_addr = format!("127.0.0.1:{}", ports::get_port());
1270 let opts = PostgresOptions {
1271 addr: fe_pg_addr.clone(),
1272 ..Default::default()
1273 };
1274 let tls_server_config = Arc::new(
1275 ReloadableTlsServerConfig::try_new(opts.tls.clone())
1276 .expect("Failed to load certificates and keys"),
1277 );
1278
1279 let mut pg_server = Box::new(PostgresServer::new(
1280 instance.fe_instance().clone(),
1281 opts.tls.should_force_tls(),
1282 tls_server_config,
1283 0,
1284 runtime,
1285 None,
1286 None,
1287 ));
1288
1289 pg_server
1290 .start(fe_pg_addr.parse::<SocketAddr>().unwrap())
1291 .await
1292 .unwrap();
1293
1294 (instance.guard, app, Arc::new(pg_server))
1295}
1296
1297pub(crate) async fn prepare_another_catalog_and_schema(instance: &Instance) {
1298 let catalog_manager = instance
1299 .catalog_manager()
1300 .as_any()
1301 .downcast_ref::<KvBackendCatalogManager>()
1302 .unwrap();
1303
1304 let table_metadata_manager = catalog_manager.table_metadata_manager_ref();
1305 prepare_another_catalog_and_schema_with_manager(table_metadata_manager).await;
1306}
1307
1308pub(crate) async fn prepare_another_catalog_and_schema_with_kv_backend(kv_backend: KvBackendRef) {
1309 let table_metadata_manager = TableMetadataManager::new(kv_backend);
1310 prepare_another_catalog_and_schema_with_manager(&table_metadata_manager).await;
1311}
1312
1313async fn prepare_another_catalog_and_schema_with_manager(
1314 table_metadata_manager: &TableMetadataManager,
1315) {
1316 table_metadata_manager
1317 .catalog_manager()
1318 .create(CatalogNameKey::new("another_catalog"), true)
1319 .await
1320 .unwrap();
1321 table_metadata_manager
1322 .schema_manager()
1323 .create(
1324 SchemaNameKey::new("another_catalog", "another_schema"),
1325 None,
1326 true,
1327 )
1328 .await
1329 .unwrap();
1330}
1331
1332pub async fn execute_sql(instance: &Arc<Instance>, sql: &str) -> Output {
1333 SqlQueryHandler::do_query(instance.as_ref(), sql, QueryContext::arc())
1334 .await
1335 .remove(0)
1336 .unwrap()
1337}
1338
1339pub async fn try_execute_sql(
1340 instance: &Arc<Instance>,
1341 sql: &str,
1342) -> servers::error::Result<Output> {
1343 SqlQueryHandler::do_query(instance.as_ref(), sql, QueryContext::arc())
1344 .await
1345 .remove(0)
1346}
1347
1348pub async fn execute_sql_and_expect(instance: &Arc<Instance>, sql: &str, expected: &str) {
1349 let output = execute_sql(instance, sql).await;
1350 let output = output.data.pretty_print().await;
1351 assert_eq!(output, expected.trim());
1352}