- Add a new service manager crate for dynamic service management - Integrate service manager with Rhai for scripting - Provide examples for circle worker management and basic usage - Add comprehensive tests for service lifecycle and error handling - Implement cross-platform support for macOS and Linux (zinit/systemd)
246 lines
8.3 KiB
Rust
246 lines
8.3 KiB
Rust
use rhai::{Engine, EvalAltResult};
|
|
use std::fs;
|
|
use std::path::Path;
|
|
|
|
/// Helper function to create a Rhai engine for service manager testing
|
|
fn create_service_manager_engine() -> Result<Engine, Box<EvalAltResult>> {
|
|
let engine = Engine::new();
|
|
|
|
// Register any custom functions that would be needed for service manager integration
|
|
// For now, we'll keep it simple since the actual service manager integration
|
|
// would require more complex setup
|
|
|
|
Ok(engine)
|
|
}
|
|
|
|
/// Helper function to run a Rhai script file
|
|
fn run_rhai_script(script_path: &str) -> Result<rhai::Dynamic, Box<EvalAltResult>> {
|
|
let engine = create_service_manager_engine()?;
|
|
|
|
// Read the script file
|
|
let script_content = fs::read_to_string(script_path)
|
|
.map_err(|e| format!("Failed to read script file {}: {}", script_path, e))?;
|
|
|
|
// Execute the script
|
|
engine.eval::<rhai::Dynamic>(&script_content)
|
|
}
|
|
|
|
#[test]
|
|
fn test_rhai_service_manager_basic() {
|
|
let script_path = "tests/rhai/service_manager_basic.rhai";
|
|
|
|
if !Path::new(script_path).exists() {
|
|
println!("⚠ Skipping test: Rhai script not found at {}", script_path);
|
|
return;
|
|
}
|
|
|
|
println!("Running Rhai service manager basic test...");
|
|
|
|
match run_rhai_script(script_path) {
|
|
Ok(result) => {
|
|
println!("✓ Rhai basic test completed successfully");
|
|
|
|
// Try to extract test results if the script returns them
|
|
if let Some(map) = result.try_cast::<rhai::Map>() {
|
|
println!("Test results received from Rhai script:");
|
|
for (key, value) in map.iter() {
|
|
println!(" {}: {:?}", key, value);
|
|
}
|
|
|
|
// Check if all tests passed
|
|
let all_passed = map.values().all(|v| {
|
|
if let Some(s) = v.clone().try_cast::<String>() {
|
|
s == "PASS"
|
|
} else {
|
|
false
|
|
}
|
|
});
|
|
|
|
if all_passed {
|
|
println!("✓ All Rhai tests reported as PASS");
|
|
} else {
|
|
println!("⚠ Some Rhai tests did not pass");
|
|
}
|
|
}
|
|
}
|
|
Err(e) => {
|
|
println!("✗ Rhai basic test failed: {}", e);
|
|
panic!("Rhai script execution failed");
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_rhai_service_lifecycle() {
|
|
let script_path = "tests/rhai/service_lifecycle.rhai";
|
|
|
|
if !Path::new(script_path).exists() {
|
|
println!("⚠ Skipping test: Rhai script not found at {}", script_path);
|
|
return;
|
|
}
|
|
|
|
println!("Running Rhai service lifecycle test...");
|
|
|
|
match run_rhai_script(script_path) {
|
|
Ok(result) => {
|
|
println!("✓ Rhai lifecycle test completed successfully");
|
|
|
|
// Try to extract test results if the script returns them
|
|
if let Some(map) = result.try_cast::<rhai::Map>() {
|
|
println!("Lifecycle test results received from Rhai script:");
|
|
|
|
// Extract summary if available
|
|
if let Some(summary) = map.get("summary") {
|
|
if let Some(summary_map) = summary.clone().try_cast::<rhai::Map>() {
|
|
println!("Summary:");
|
|
for (key, value) in summary_map.iter() {
|
|
println!(" {}: {:?}", key, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Extract performance metrics if available
|
|
if let Some(performance) = map.get("performance") {
|
|
if let Some(perf_map) = performance.clone().try_cast::<rhai::Map>() {
|
|
println!("Performance:");
|
|
for (key, value) in perf_map.iter() {
|
|
println!(" {}: {:?}", key, value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Err(e) => {
|
|
println!("✗ Rhai lifecycle test failed: {}", e);
|
|
panic!("Rhai script execution failed");
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_rhai_engine_functionality() {
|
|
println!("Testing basic Rhai engine functionality...");
|
|
|
|
let engine = create_service_manager_engine().expect("Failed to create Rhai engine");
|
|
|
|
// Test basic Rhai functionality
|
|
let test_script = r#"
|
|
let test_results = #{
|
|
basic_math: 2 + 2 == 4,
|
|
string_ops: "hello".len() == 5,
|
|
array_ops: [1, 2, 3].len() == 3,
|
|
map_ops: #{ a: 1, b: 2 }.len() == 2
|
|
};
|
|
|
|
let all_passed = true;
|
|
for result in test_results.values() {
|
|
if !result {
|
|
all_passed = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#{
|
|
results: test_results,
|
|
all_passed: all_passed
|
|
}
|
|
"#;
|
|
|
|
match engine.eval::<rhai::Dynamic>(test_script) {
|
|
Ok(result) => {
|
|
if let Some(map) = result.try_cast::<rhai::Map>() {
|
|
if let Some(all_passed) = map.get("all_passed") {
|
|
if let Some(passed) = all_passed.clone().try_cast::<bool>() {
|
|
if passed {
|
|
println!("✓ All basic Rhai functionality tests passed");
|
|
} else {
|
|
println!("✗ Some basic Rhai functionality tests failed");
|
|
panic!("Basic Rhai tests failed");
|
|
}
|
|
}
|
|
}
|
|
|
|
if let Some(results) = map.get("results") {
|
|
if let Some(results_map) = results.clone().try_cast::<rhai::Map>() {
|
|
println!("Detailed results:");
|
|
for (test_name, result) in results_map.iter() {
|
|
let status = if let Some(passed) = result.clone().try_cast::<bool>() {
|
|
if passed {
|
|
"✓"
|
|
} else {
|
|
"✗"
|
|
}
|
|
} else {
|
|
"?"
|
|
};
|
|
println!(" {} {}: {:?}", status, test_name, result);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Err(e) => {
|
|
println!("✗ Basic Rhai functionality test failed: {}", e);
|
|
panic!("Basic Rhai test failed");
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_rhai_script_error_handling() {
|
|
println!("Testing Rhai error handling...");
|
|
|
|
let engine = create_service_manager_engine().expect("Failed to create Rhai engine");
|
|
|
|
// Test script with intentional error
|
|
let error_script = r#"
|
|
let result = "test";
|
|
result.non_existent_method(); // This should cause an error
|
|
"#;
|
|
|
|
match engine.eval::<rhai::Dynamic>(error_script) {
|
|
Ok(_) => {
|
|
println!("⚠ Expected error but script succeeded");
|
|
panic!("Error handling test failed - expected error but got success");
|
|
}
|
|
Err(e) => {
|
|
println!("✓ Error correctly caught: {}", e);
|
|
// Verify it's the expected type of error
|
|
assert!(e.to_string().contains("method") || e.to_string().contains("function"));
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_rhai_script_files_exist() {
|
|
println!("Checking that Rhai test scripts exist...");
|
|
|
|
let script_files = [
|
|
"tests/rhai/service_manager_basic.rhai",
|
|
"tests/rhai/service_lifecycle.rhai",
|
|
];
|
|
|
|
for script_file in &script_files {
|
|
if Path::new(script_file).exists() {
|
|
println!("✓ Found script: {}", script_file);
|
|
|
|
// Verify the file is readable and not empty
|
|
match fs::read_to_string(script_file) {
|
|
Ok(content) => {
|
|
if content.trim().is_empty() {
|
|
panic!("Script file {} is empty", script_file);
|
|
}
|
|
println!(" Content length: {} characters", content.len());
|
|
}
|
|
Err(e) => {
|
|
panic!("Failed to read script file {}: {}", script_file, e);
|
|
}
|
|
}
|
|
} else {
|
|
panic!("Required script file not found: {}", script_file);
|
|
}
|
|
}
|
|
|
|
println!("✓ All required Rhai script files exist and are readable");
|
|
}
|