use std::time::Duration;
use tokio::time::timeout;
#[tokio::test]
async fn test_context_instance_none_by_default() {}
#[tokio::test]
async fn test_instance_name_formatting() {
let base = "camera_node";
let instance = "left";
let expected_node_id = format!("{}/{}", base, instance);
assert_eq!(expected_node_id, "camera_node/left");
}
#[tokio::test]
async fn test_multiple_instance_names() {
let test_cases = vec![
("node", "instance1", "node/instance1"),
("robot", "left_arm", "robot/left_arm"),
("sensor", "camera_0", "sensor/camera_0"),
];
for (base, instance, expected) in test_cases {
let result = format!("{}/{}", base, instance);
assert_eq!(result, expected);
}
}
#[tokio::test]
async fn test_shutdown_signal_propagation() {
use std::sync::Arc;
use tokio::sync::RwLock;
let shutdown = Arc::new(RwLock::new(false));
assert!(!*shutdown.read().await);
*shutdown.write().await = true;
assert!(*shutdown.read().await);
}
#[tokio::test]
async fn test_shutdown_wait_behavior() {
use std::sync::Arc;
use tokio::sync::RwLock;
let shutdown = Arc::new(RwLock::new(false));
let shutdown_clone = Arc::clone(&shutdown);
tokio::spawn(async move {
tokio::time::sleep(Duration::from_millis(50)).await;
*shutdown_clone.write().await = true;
});
let start = std::time::Instant::now();
let result = timeout(Duration::from_millis(200), async {
loop {
if *shutdown.read().await {
break;
}
tokio::time::sleep(Duration::from_millis(10)).await;
}
})
.await;
assert!(result.is_ok());
let elapsed = start.elapsed();
assert!(elapsed >= Duration::from_millis(50));
assert!(elapsed < Duration::from_millis(150));
}
#[tokio::test]
async fn test_node_id_validation() {
let test_ids = vec!["test-node", "robot_1", "sensor.camera", "node/with/slashes"];
for id in test_ids {
assert_eq!(id, id);
}
}
#[tokio::test]
async fn test_consumer_group_naming() {
let node_id = "test_node";
let topic_path = "/sensor/camera/rgb";
let expected = format!("{}-{}", node_id, topic_path.replace('/', "-"));
assert_eq!(expected, "test_node--sensor-camera-rgb");
}
#[tokio::test]
async fn test_consumer_group_naming_with_instance() {
let node_id = "camera_node/left";
let topic_path = "/sensor/lidar";
let expected = format!("{}-{}", node_id, topic_path.replace('/', "-"));
assert_eq!(expected, "camera_node/left--sensor-lidar");
}
#[tokio::test]
async fn test_scoped_topic_path_generation() {
let topic_path = "/sensor/camera/rgb";
let instance = "left";
let scoped_path = format!("{}/{}", topic_path, instance);
assert_eq!(scoped_path, "/sensor/camera/rgb/left");
}
#[tokio::test]
async fn test_scoped_topic_path_no_instance() {
let topic_path = "/sensor/camera/rgb";
let instance: Option<&str> = None;
let scoped_path = if let Some(inst) = instance {
format!("{}/{}", topic_path, inst)
} else {
topic_path.to_string()
};
assert_eq!(scoped_path, "/sensor/camera/rgb");
}
#[tokio::test]
async fn test_instance_topic_path_generation() {
let topic_path = "/actuator/motor/cmd";
let instance = "front_left";
let instance_path = format!("{}/{}", topic_path, instance);
assert_eq!(instance_path, "/actuator/motor/cmd/front_left");
}
#[tokio::test]
async fn test_redis_url_from_env() {
std::env::set_var("REDIS_URL", "redis://custom:6379");
let url = std::env::var("REDIS_URL").unwrap();
assert_eq!(url, "redis://custom:6379");
std::env::remove_var("REDIS_URL");
}
#[tokio::test]
async fn test_redis_url_default() {
std::env::remove_var("REDIS_URL");
let url = std::env::var("REDIS_URL").unwrap_or_else(|_| "redis://localhost:6379".to_string());
assert_eq!(url, "redis://localhost:6379");
}
#[tokio::test]
async fn test_mecha10_environment_variable() {
std::env::set_var("MECHA10_ENVIRONMENT", "production");
let env = std::env::var("MECHA10_ENVIRONMENT").unwrap_or_else(|_| "development".to_string());
assert_eq!(env, "production");
std::env::remove_var("MECHA10_ENVIRONMENT");
}
#[tokio::test]
async fn test_mecha10_environment_default() {
std::env::remove_var("MECHA10_ENVIRONMENT");
let env = std::env::var("MECHA10_ENVIRONMENT").unwrap_or_else(|_| "development".to_string());
assert_eq!(env, "development");
}
#[tokio::test]
async fn test_state_dir_from_env() {
std::env::set_var("MECHA10_STATE_DIR", "/custom/state");
let state_dir = std::env::var("MECHA10_STATE_DIR").unwrap_or_else(|_| "./state".to_string());
assert_eq!(state_dir, "/custom/state");
std::env::remove_var("MECHA10_STATE_DIR");
}
#[tokio::test]
async fn test_infrastructure_config_path_generation() {
let environments = vec![
("development", "config/infrastructure.development.yaml"),
("local", "config/infrastructure.local.yaml"),
("production", "config/infrastructure.production.yaml"),
];
for (env, expected_path) in environments {
let path = format!("config/infrastructure.{}.yaml", env);
assert_eq!(path, expected_path);
}
}
#[tokio::test]
async fn test_logging_span_name() {
let node_id = "test_node";
let span = tracing::info_span!("node", node_id = %node_id);
let _ = span;
}
#[tokio::test]
async fn test_arc_clone_behavior() {
use std::sync::Arc;
use tokio::sync::RwLock;
let original = Arc::new(RwLock::new(42));
let cloned = Arc::clone(&original);
*cloned.write().await = 100;
assert_eq!(*original.read().await, 100);
}
#[tokio::test]
async fn test_shared_shutdown_flag() {
use std::sync::Arc;
use tokio::sync::RwLock;
let shutdown = Arc::new(RwLock::new(false));
let shutdown_clone1 = Arc::clone(&shutdown);
let shutdown_clone2 = Arc::clone(&shutdown);
*shutdown_clone1.write().await = true;
assert!(*shutdown_clone2.read().await);
assert!(*shutdown.read().await);
}
#[tokio::test]
async fn test_redis_config_default() {
use mecha10_core::context::RedisConfig;
let config = RedisConfig::default();
assert_eq!(config.url, "redis://localhost:6379");
assert_eq!(config.max_connections, 10);
assert_eq!(config.connection_timeout_ms, 5000);
}
#[tokio::test]
async fn test_redis_config_custom() {
use mecha10_core::context::RedisConfig;
let config = RedisConfig {
url: "redis://custom:6380".to_string(),
max_connections: 20,
connection_timeout_ms: 10000,
};
assert_eq!(config.url, "redis://custom:6380");
assert_eq!(config.max_connections, 20);
assert_eq!(config.connection_timeout_ms, 10000);
}
#[tokio::test]
async fn test_glob_pattern_basic() {
let patterns = vec![
("/sensor/camera/*", true),
("/sensor/**", true),
("/actuator/motor/*", true),
("*", true),
];
for (pattern, _should_be_valid) in patterns {
assert!(pattern.contains('/') || pattern == "*");
}
}
#[tokio::test]
async fn test_error_message_formatting() {
use mecha10_core::error::Mecha10Error;
let error = Mecha10Error::MessagingError {
message: "Connection failed".to_string(),
suggestion: "Check Redis is running".to_string(),
};
let formatted = format!("{}", error);
assert!(formatted.contains("Connection failed"));
}
#[tokio::test]
async fn test_configuration_error() {
use mecha10_core::error::Mecha10Error;
let error = Mecha10Error::Configuration("Invalid config".to_string());
let formatted = format!("{}", error);
assert!(formatted.contains("Invalid config"));
}
#[tokio::test]
async fn test_context_builder_pattern() {
use mecha10_core::context::ContextBuilder;
let _builder = ContextBuilder::new("test-node");
}
#[tokio::test]
async fn test_context_builder_with_instance() {
use mecha10_core::context::ContextBuilder;
let _builder = ContextBuilder::new("test-node").with_instance("inst1");
}
#[tokio::test]
async fn test_context_builder_with_redis_url() {
use mecha10_core::context::ContextBuilder;
let _builder = ContextBuilder::new("test-node").with_redis("redis://custom:6379");
}
#[tokio::test]
async fn test_context_builder_with_state_dir() {
use mecha10_core::context::ContextBuilder;
let _builder = ContextBuilder::new("test-node").with_state_dir("/custom/state");
}
#[tokio::test]
async fn test_context_builder_local_dev_preset() {
use mecha10_core::context::ContextBuilder;
let _builder = ContextBuilder::local_dev("dev-node");
}
#[tokio::test]
async fn test_context_builder_production_preset() {
use mecha10_core::context::ContextBuilder;
let _builder = ContextBuilder::production("prod-node");
}
#[tokio::test]
async fn test_context_builder_test_preset() {
use mecha10_core::context::ContextBuilder;
let _builder = ContextBuilder::test("test-node");
}
#[tokio::test]
async fn test_context_builder_chaining() {
use mecha10_core::context::ContextBuilder;
let _builder = ContextBuilder::new("test-node")
.with_instance("inst1")
.with_redis("redis://localhost:6379")
.with_state_dir("./state");
}
#[tokio::test]
async fn test_concurrent_shutdown_checks() {
use std::sync::Arc;
use tokio::sync::RwLock;
let shutdown = Arc::new(RwLock::new(false));
let mut handles = vec![];
for _ in 0..10 {
let shutdown_clone = Arc::clone(&shutdown);
let handle = tokio::spawn(async move { *shutdown_clone.read().await });
handles.push(handle);
}
for handle in handles {
assert!(!handle.await.unwrap());
}
}
#[tokio::test]
async fn test_concurrent_arc_access() {
use std::sync::Arc;
use tokio::sync::RwLock;
let counter = Arc::new(RwLock::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter_clone = Arc::clone(&counter);
let handle = tokio::spawn(async move {
*counter_clone.write().await += 1;
});
handles.push(handle);
}
for handle in handles {
handle.await.unwrap();
}
assert_eq!(*counter.read().await, 10);
}