Unverified Commit 5b5ca802 authored by Keiven C's avatar Keiven C Committed by GitHub
Browse files

refactor: share common drt test functions (#2583)


Co-authored-by: default avatarKeiven Chang <keivenchang@users.noreply.github.com>
parent b98188c8
...@@ -355,3 +355,20 @@ impl DistributedConfig { ...@@ -355,3 +355,20 @@ impl DistributedConfig {
config config
} }
} }
#[cfg(test)]
pub mod test_helpers {
//! Common test helper functions for DistributedRuntime tests
// TODO: Use in-memory DistributedRuntime for tests instead of full runtime when available.
/// Helper function to create a DRT instance for tests
/// Uses from_current to leverage existing tokio runtime
/// Note: Settings are read from environment variables inside DistributedRuntime::from_settings_without_discovery
#[cfg(feature = "integration")]
pub async fn create_test_drt_async() -> crate::DistributedRuntime {
let rt = crate::Runtime::from_current().unwrap();
crate::DistributedRuntime::from_settings_without_discovery(rt)
.await
.unwrap()
}
}
...@@ -578,15 +578,6 @@ mod test_helpers { ...@@ -578,15 +578,6 @@ mod test_helpers {
use super::prometheus_names::{nats_client, nats_service}; use super::prometheus_names::{nats_client, nats_service};
use super::*; use super::*;
/// Helper function to create a DRT instance for testing in async contexts
#[cfg(feature = "integration")]
pub async fn create_test_drt_async() -> crate::DistributedRuntime {
let rt = crate::Runtime::from_current().unwrap();
crate::DistributedRuntime::from_settings_without_discovery(rt)
.await
.unwrap()
}
/// Base function to filter Prometheus output lines based on a predicate. /// Base function to filter Prometheus output lines based on a predicate.
/// Returns lines that match the predicate, converted to String. /// Returns lines that match the predicate, converted to String.
fn filter_prometheus_lines<F>(input: &str, mut predicate: F) -> Vec<String> fn filter_prometheus_lines<F>(input: &str, mut predicate: F) -> Vec<String>
...@@ -822,7 +813,6 @@ mod test_metricsregistry_units { ...@@ -822,7 +813,6 @@ mod test_metricsregistry_units {
println!("✓ Prometheus metric parsing works correctly!"); println!("✓ Prometheus metric parsing works correctly!");
} }
#[cfg(feature = "integration")]
#[test] #[test]
fn test_metrics_registry_entry_callbacks() { fn test_metrics_registry_entry_callbacks() {
use crate::MetricsRegistryEntry; use crate::MetricsRegistryEntry;
...@@ -923,11 +913,12 @@ mod test_metricsregistry_units { ...@@ -923,11 +913,12 @@ mod test_metricsregistry_units {
#[cfg(test)] #[cfg(test)]
mod test_metricsregistry_prefixes { mod test_metricsregistry_prefixes {
use super::*; use super::*;
use crate::distributed::test_helpers::create_test_drt_async;
use prometheus::core::Collector; use prometheus::core::Collector;
#[tokio::test] #[tokio::test]
async fn test_hierarchical_prefixes_and_parent_hierarchies() { async fn test_hierarchical_prefixes_and_parent_hierarchies() {
let drt = super::test_helpers::create_test_drt_async().await; let drt = create_test_drt_async().await;
const DRT_NAME: &str = ""; const DRT_NAME: &str = "";
const NAMESPACE_NAME: &str = "ns901"; const NAMESPACE_NAME: &str = "ns901";
...@@ -1002,7 +993,7 @@ mod test_metricsregistry_prefixes { ...@@ -1002,7 +993,7 @@ mod test_metricsregistry_prefixes {
#[tokio::test] #[tokio::test]
async fn test_recursive_namespace() { async fn test_recursive_namespace() {
// Create a distributed runtime for testing // Create a distributed runtime for testing
let drt = super::test_helpers::create_test_drt_async().await; let drt = create_test_drt_async().await;
// Create a deeply chained namespace: ns1.ns2.ns3 // Create a deeply chained namespace: ns1.ns2.ns3
let ns1 = drt.namespace("ns1").unwrap(); let ns1 = drt.namespace("ns1").unwrap();
...@@ -1054,13 +1045,14 @@ mod test_metricsregistry_prometheus_fmt_outputs { ...@@ -1054,13 +1045,14 @@ mod test_metricsregistry_prometheus_fmt_outputs {
use super::prometheus_names::{nats_client, nats_service}; use super::prometheus_names::{nats_client, nats_service};
use super::prometheus_names::{COMPONENT_NATS_METRICS, DRT_NATS_METRICS}; use super::prometheus_names::{COMPONENT_NATS_METRICS, DRT_NATS_METRICS};
use super::*; use super::*;
use crate::distributed::test_helpers::create_test_drt_async;
use prometheus::Counter; use prometheus::Counter;
use std::sync::Arc; use std::sync::Arc;
#[tokio::test] #[tokio::test]
async fn test_prometheusfactory_using_metrics_registry_trait() { async fn test_prometheusfactory_using_metrics_registry_trait() {
// Setup real DRT and registry using the test-friendly constructor // Setup real DRT and registry using the test-friendly constructor
let drt = super::test_helpers::create_test_drt_async().await; let drt = create_test_drt_async().await;
// Use a simple constant namespace name // Use a simple constant namespace name
let namespace_name = "ns345"; let namespace_name = "ns345";
...@@ -1312,13 +1304,14 @@ mod test_metricsregistry_nats { ...@@ -1312,13 +1304,14 @@ mod test_metricsregistry_nats {
use super::prometheus_names::{nats_client, nats_service}; use super::prometheus_names::{nats_client, nats_service};
use super::prometheus_names::{COMPONENT_NATS_METRICS, DRT_NATS_METRICS}; use super::prometheus_names::{COMPONENT_NATS_METRICS, DRT_NATS_METRICS};
use super::*; use super::*;
use crate::distributed::test_helpers::create_test_drt_async;
use crate::pipeline::PushRouter; use crate::pipeline::PushRouter;
use crate::{DistributedRuntime, Runtime}; use crate::{DistributedRuntime, Runtime};
use tokio::time::{sleep, Duration}; use tokio::time::{sleep, Duration};
#[tokio::test] #[tokio::test]
async fn test_drt_nats_metrics() { async fn test_drt_nats_metrics() {
// Setup real DRT and registry using the test-friendly constructor // Setup real DRT and registry using the test-friendly constructor
let drt = super::test_helpers::create_test_drt_async().await; let drt = create_test_drt_async().await;
// Get DRT output which should include NATS client metrics // Get DRT output which should include NATS client metrics
let drt_output = drt.prometheus_metrics_fmt().unwrap(); let drt_output = drt.prometheus_metrics_fmt().unwrap();
...@@ -1382,7 +1375,7 @@ mod test_metricsregistry_nats { ...@@ -1382,7 +1375,7 @@ mod test_metricsregistry_nats {
// the values of the metrics. // the values of the metrics.
// Setup real DRT and registry using the test-friendly constructor // Setup real DRT and registry using the test-friendly constructor
let drt = super::test_helpers::create_test_drt_async().await; let drt = create_test_drt_async().await;
// Create a namespace and components from the DRT // Create a namespace and components from the DRT
let namespace = drt.namespace("ns789").unwrap(); let namespace = drt.namespace("ns789").unwrap();
......
...@@ -15,18 +15,14 @@ ...@@ -15,18 +15,14 @@
use crate::config::HealthStatus; use crate::config::HealthStatus;
use crate::logging::make_request_span; use crate::logging::make_request_span;
use crate::logging::TraceParent;
use crate::metrics::MetricsRegistry; use crate::metrics::MetricsRegistry;
use crate::traits::DistributedRuntimeProvider; use crate::traits::DistributedRuntimeProvider;
use axum::{body, http::StatusCode, response::IntoResponse, routing::get, Router}; use axum::{http::StatusCode, response::IntoResponse, routing::get, Router};
use serde_json::json; use serde_json::json;
use std::collections::HashMap; use std::sync::{Arc, OnceLock};
use std::sync::Arc;
use std::sync::OnceLock;
use std::time::Instant; use std::time::Instant;
use tokio::{net::TcpListener, task::JoinHandle}; use tokio::{net::TcpListener, task::JoinHandle};
use tokio_util::sync::CancellationToken; use tokio_util::sync::CancellationToken;
use tower_http::trace::DefaultMakeSpan;
use tower_http::trace::TraceLayer; use tower_http::trace::TraceLayer;
/// System status server information containing socket address and handle /// System status server information containing socket address and handle
...@@ -296,61 +292,10 @@ async fn metrics_handler(state: Arc<SystemStatusState>) -> impl IntoResponse { ...@@ -296,61 +292,10 @@ async fn metrics_handler(state: Arc<SystemStatusState>) -> impl IntoResponse {
} }
// Regular tests: cargo test system_status_server --lib // Regular tests: cargo test system_status_server --lib
// Integration tests: cargo test system_status_server --lib --features integration
#[cfg(test)]
/// Helper function to create a DRT instance for basic unit tests
/// Uses from_current to leverage existing tokio runtime without environment configuration
async fn create_test_drt_async() -> crate::DistributedRuntime {
let rt = crate::Runtime::from_current().unwrap();
crate::DistributedRuntime::from_settings_without_discovery(rt)
.await
.unwrap()
}
#[cfg(test)]
/// Helper function to create a DRT instance for integration tests
/// Uses spawn_blocking to create runtime safely without ownership issues
/// Enables system status server for integration testing
/// Note: This function uses environment variables to configure and create the DistributedRuntime.
async fn create_test_drt_with_settings_async() -> crate::DistributedRuntime {
// Create runtime in blocking context where it can be safely dropped
let handle = tokio::task::spawn_blocking(|| {
// Load configuration from environment/settings
let config = crate::config::RuntimeConfig::from_settings().unwrap();
// Create runtime with the configuration and extract handle
let runtime = config.create_runtime().unwrap();
let handle = runtime.handle().clone();
// Runtime will be automatically dropped when it goes out of scope
handle
})
.await
.unwrap();
// Create Runtime using external handle (no ownership)
let rt = crate::Runtime::from_handle(handle).unwrap();
crate::DistributedRuntime::from_settings_without_discovery(rt)
.await
.unwrap()
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::logging::tests::load_log; use tokio::time::Duration;
use crate::metrics::MetricsRegistry;
use anyhow::{anyhow, Result};
use chrono::{DateTime, Utc};
use jsonschema::{Draft, JSONSchema};
use rstest::rstest;
use serde_json::Value;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::sync::Arc;
use stdio_override::*;
use tokio::time::{sleep, Duration};
// This is a basic test to verify the HTTP server is working before testing other more complicated tests // This is a basic test to verify the HTTP server is working before testing other more complicated tests
#[tokio::test] #[tokio::test]
...@@ -381,8 +326,19 @@ mod tests { ...@@ -381,8 +326,19 @@ mod tests {
"HTTP server should shut down when cancel token is cancelled" "HTTP server should shut down when cancel token is cancelled"
); );
} }
}
// Integration tests: cargo test system_status_server --lib --features integration
#[cfg(all(test, feature = "integration"))]
mod integration_tests {
use super::*;
use crate::distributed::test_helpers::create_test_drt_async;
use crate::metrics::MetricsRegistry;
use anyhow::Result;
use rstest::rstest;
use std::sync::Arc;
use tokio::time::Duration;
#[cfg(feature = "integration")]
#[tokio::test] #[tokio::test]
async fn test_uptime_without_initialization() { async fn test_uptime_without_initialization() {
// Test that uptime returns an error if start time is not initialized // Test that uptime returns an error if start time is not initialized
...@@ -398,7 +354,6 @@ mod tests { ...@@ -398,7 +354,6 @@ mod tests {
.await; .await;
} }
#[cfg(feature = "integration")]
#[tokio::test] #[tokio::test]
async fn test_runtime_metrics_initialization_and_namespace() { async fn test_runtime_metrics_initialization_and_namespace() {
// Test that metrics have correct namespace // Test that metrics have correct namespace
...@@ -439,7 +394,6 @@ mod tests { ...@@ -439,7 +394,6 @@ mod tests {
.await; .await;
} }
#[cfg(feature = "integration")]
#[tokio::test] #[tokio::test]
async fn test_start_time_initialization() { async fn test_start_time_initialization() {
// Test that start time can only be initialized once // Test that start time can only be initialized once
...@@ -516,7 +470,7 @@ mod tests { ...@@ -516,7 +470,7 @@ mod tests {
("DYN_SYSTEM_LIVE_PATH", custom_live_path), ("DYN_SYSTEM_LIVE_PATH", custom_live_path),
], ],
(async || { (async || {
let drt = Arc::new(create_test_drt_with_settings_async().await); let drt = Arc::new(create_test_drt_async().await);
// Get system status server info from DRT (instead of manually spawning) // Get system status server info from DRT (instead of manually spawning)
let system_info = drt let system_info = drt
...@@ -575,7 +529,6 @@ mod tests { ...@@ -575,7 +529,6 @@ mod tests {
} }
#[tokio::test] #[tokio::test]
#[cfg(feature = "integration")]
async fn test_health_endpoint_tracing() -> Result<()> { async fn test_health_endpoint_tracing() -> Result<()> {
use std::sync::Arc; use std::sync::Arc;
...@@ -596,7 +549,7 @@ mod tests { ...@@ -596,7 +549,7 @@ mod tests {
crate::logging::init(); crate::logging::init();
let drt = Arc::new(create_test_drt_with_settings_async().await); let drt = Arc::new(create_test_drt_async().await);
// Get system status server info from DRT (instead of manually spawning) // Get system status server info from DRT (instead of manually spawning)
let system_info = drt let system_info = drt
...@@ -631,7 +584,6 @@ mod tests { ...@@ -631,7 +584,6 @@ mod tests {
Ok(()) Ok(())
} }
#[cfg(feature = "integration")]
#[tokio::test] #[tokio::test]
async fn test_health_endpoint_with_changing_health_status() { async fn test_health_endpoint_with_changing_health_status() {
// Test health endpoint starts in not ready status, then becomes ready // Test health endpoint starts in not ready status, then becomes ready
...@@ -646,7 +598,7 @@ mod tests { ...@@ -646,7 +598,7 @@ mod tests {
("DYN_SYSTEM_USE_ENDPOINT_HEALTH_STATUS", Some(ENDPOINT_HEALTH_CONFIG)), ("DYN_SYSTEM_USE_ENDPOINT_HEALTH_STATUS", Some(ENDPOINT_HEALTH_CONFIG)),
], ],
async { async {
let drt = Arc::new(create_test_drt_with_settings_async().await); let drt = Arc::new(create_test_drt_async().await);
// Check if system status server was started // Check if system status server was started
let system_info_opt = drt.system_status_server_info(); let system_info_opt = drt.system_status_server_info();
...@@ -745,7 +697,6 @@ mod tests { ...@@ -745,7 +697,6 @@ mod tests {
.await; .await;
} }
#[cfg(feature = "integration")]
#[tokio::test] #[tokio::test]
async fn test_spawn_system_status_server_endpoints() { async fn test_spawn_system_status_server_endpoints() {
// use reqwest for HTTP requests // use reqwest for HTTP requests
...@@ -756,7 +707,7 @@ mod tests { ...@@ -756,7 +707,7 @@ mod tests {
("DYN_SYSTEM_STARTING_HEALTH_STATUS", Some("ready")), ("DYN_SYSTEM_STARTING_HEALTH_STATUS", Some("ready")),
], ],
async { async {
let drt = Arc::new(create_test_drt_with_settings_async().await); let drt = Arc::new(create_test_drt_async().await);
// Get system status server info from DRT (instead of manually spawning) // Get system status server info from DRT (instead of manually spawning)
let system_info = drt let system_info = drt
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment