feat: Add process package to monorepo
Some checks are pending
Rhai Tests / Run Rhai Tests (push) Waiting to run
Some checks are pending
Rhai Tests / Run Rhai Tests (push) Waiting to run
- Add `sal-process` package for cross-platform process management. - Update workspace members in `Cargo.toml`. - Mark process package as complete in MONOREPO_CONVERSION_PLAN.md - Remove license information from `mycelium` and `os` READMEs.
This commit is contained in:
278
process/tests/mgmt_tests.rs
Normal file
278
process/tests/mgmt_tests.rs
Normal file
@@ -0,0 +1,278 @@
|
||||
use sal_process::{kill, process_get, process_list, which, ProcessError};
|
||||
|
||||
#[test]
|
||||
fn test_which_existing_command() {
|
||||
// Test with a command that should exist on all systems
|
||||
#[cfg(target_os = "windows")]
|
||||
let cmd = "cmd";
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let cmd = "sh";
|
||||
|
||||
let result = which(cmd);
|
||||
assert!(result.is_some());
|
||||
assert!(!result.unwrap().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_which_nonexistent_command() {
|
||||
let result = which("nonexistent_command_12345");
|
||||
assert!(result.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_which_common_commands() {
|
||||
// Test common commands that should exist
|
||||
let common_commands = if cfg!(target_os = "windows") {
|
||||
vec!["cmd", "powershell"]
|
||||
} else {
|
||||
vec!["sh", "ls", "echo"]
|
||||
};
|
||||
|
||||
for cmd in common_commands {
|
||||
let result = which(cmd);
|
||||
assert!(result.is_some(), "Command '{}' should be found", cmd);
|
||||
assert!(!result.unwrap().is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_list_all() {
|
||||
let result = process_list("").unwrap();
|
||||
assert!(
|
||||
!result.is_empty(),
|
||||
"Should find at least one running process"
|
||||
);
|
||||
|
||||
// Verify process info structure
|
||||
let first_process = &result[0];
|
||||
assert!(first_process.pid > 0, "Process PID should be positive");
|
||||
assert!(
|
||||
!first_process.name.is_empty(),
|
||||
"Process name should not be empty"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_list_with_pattern() {
|
||||
// Try to find processes with common names
|
||||
let patterns = if cfg!(target_os = "windows") {
|
||||
vec!["explorer", "winlogon", "System"]
|
||||
} else {
|
||||
vec!["init", "kernel", "systemd"]
|
||||
};
|
||||
|
||||
let mut found_any = false;
|
||||
for pattern in patterns {
|
||||
if let Ok(processes) = process_list(pattern) {
|
||||
if !processes.is_empty() {
|
||||
found_any = true;
|
||||
for process in processes {
|
||||
assert!(
|
||||
process.name.contains(pattern)
|
||||
|| process
|
||||
.name
|
||||
.to_lowercase()
|
||||
.contains(&pattern.to_lowercase())
|
||||
);
|
||||
assert!(process.pid > 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// At least one pattern should match some processes
|
||||
assert!(
|
||||
found_any,
|
||||
"Should find at least one process with common patterns"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_list_nonexistent_pattern() {
|
||||
let result = process_list("nonexistent_process_12345").unwrap();
|
||||
assert!(
|
||||
result.is_empty(),
|
||||
"Should not find any processes with nonexistent pattern"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_info_structure() {
|
||||
let processes = process_list("").unwrap();
|
||||
assert!(!processes.is_empty());
|
||||
|
||||
let process = &processes[0];
|
||||
|
||||
// Test ProcessInfo fields
|
||||
assert!(process.pid > 0);
|
||||
assert!(!process.name.is_empty());
|
||||
// memory and cpu are placeholders, so we just check they exist
|
||||
assert!(process.memory >= 0.0);
|
||||
assert!(process.cpu >= 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_get_single_match() {
|
||||
// Find a process that should be unique
|
||||
let processes = process_list("").unwrap();
|
||||
assert!(!processes.is_empty());
|
||||
|
||||
// Try to find a process with a unique enough name
|
||||
let mut unique_process = None;
|
||||
for process in &processes {
|
||||
let matches = process_list(&process.name).unwrap();
|
||||
if matches.len() == 1 {
|
||||
unique_process = Some(process.clone());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(process) = unique_process {
|
||||
let result = process_get(&process.name).unwrap();
|
||||
assert_eq!(result.pid, process.pid);
|
||||
assert_eq!(result.name, process.name);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_get_no_match() {
|
||||
let result = process_get("nonexistent_process_12345");
|
||||
assert!(result.is_err());
|
||||
match result.unwrap_err() {
|
||||
ProcessError::NoProcessFound(pattern) => {
|
||||
assert_eq!(pattern, "nonexistent_process_12345");
|
||||
}
|
||||
_ => panic!("Expected NoProcessFound error"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_get_multiple_matches() {
|
||||
// Find a pattern that matches multiple processes
|
||||
let all_processes = process_list("").unwrap();
|
||||
assert!(!all_processes.is_empty());
|
||||
|
||||
// Try common patterns that might match multiple processes
|
||||
let patterns = if cfg!(target_os = "windows") {
|
||||
vec!["svchost", "conhost"]
|
||||
} else {
|
||||
vec!["kthread", "ksoftirqd"]
|
||||
};
|
||||
|
||||
let mut _found_multiple = false;
|
||||
for pattern in patterns {
|
||||
if let Ok(processes) = process_list(pattern) {
|
||||
if processes.len() > 1 {
|
||||
let result = process_get(pattern);
|
||||
assert!(result.is_err());
|
||||
match result.unwrap_err() {
|
||||
ProcessError::MultipleProcessesFound(p, count) => {
|
||||
assert_eq!(p, pattern);
|
||||
assert_eq!(count, processes.len());
|
||||
_found_multiple = true;
|
||||
break;
|
||||
}
|
||||
_ => panic!("Expected MultipleProcessesFound error"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we can't find multiple matches with common patterns, that's okay
|
||||
// The test validates the error handling works correctly
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_kill_nonexistent_process() {
|
||||
let result = kill("nonexistent_process_12345").unwrap();
|
||||
assert!(result.contains("No matching processes") || result.contains("Successfully killed"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_list_performance() {
|
||||
use std::time::Instant;
|
||||
|
||||
let start = Instant::now();
|
||||
let _processes = process_list("").unwrap();
|
||||
let duration = start.elapsed();
|
||||
|
||||
// Process listing should complete within reasonable time (5 seconds)
|
||||
assert!(
|
||||
duration.as_secs() < 5,
|
||||
"Process listing took too long: {:?}",
|
||||
duration
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_which_performance() {
|
||||
use std::time::Instant;
|
||||
|
||||
let start = Instant::now();
|
||||
let _result = which("echo");
|
||||
let duration = start.elapsed();
|
||||
|
||||
// Which command should be very fast (1 second)
|
||||
assert!(
|
||||
duration.as_secs() < 1,
|
||||
"Which command took too long: {:?}",
|
||||
duration
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_list_filtering_accuracy() {
|
||||
// Test that filtering actually works correctly
|
||||
let all_processes = process_list("").unwrap();
|
||||
assert!(!all_processes.is_empty());
|
||||
|
||||
// Pick a process name and filter by it
|
||||
let test_process = &all_processes[0];
|
||||
let filtered_processes = process_list(&test_process.name).unwrap();
|
||||
|
||||
// All filtered processes should contain the pattern
|
||||
for process in filtered_processes {
|
||||
assert!(process.name.contains(&test_process.name));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_error_display() {
|
||||
let error = ProcessError::NoProcessFound("test".to_string());
|
||||
let error_string = format!("{}", error);
|
||||
assert!(error_string.contains("No processes found matching 'test'"));
|
||||
|
||||
let error = ProcessError::MultipleProcessesFound("test".to_string(), 5);
|
||||
let error_string = format!("{}", error);
|
||||
assert!(error_string.contains("Multiple processes (5) found matching 'test'"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cross_platform_process_operations() {
|
||||
// Test operations that should work on all platforms
|
||||
|
||||
// Test which with platform-specific commands
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
assert!(which("cmd").is_some());
|
||||
assert!(which("notepad").is_some());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
assert!(which("sh").is_some());
|
||||
assert!(which("ls").is_some());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
assert!(which("sh").is_some());
|
||||
assert!(which("ls").is_some());
|
||||
}
|
||||
|
||||
// Test process listing works on all platforms
|
||||
let processes = process_list("").unwrap();
|
||||
assert!(!processes.is_empty());
|
||||
}
|
119
process/tests/rhai/01_command_execution.rhai
Normal file
119
process/tests/rhai/01_command_execution.rhai
Normal file
@@ -0,0 +1,119 @@
|
||||
// Test script for process command execution functionality
|
||||
|
||||
print("=== Process Command Execution Tests ===");
|
||||
|
||||
// Test 1: Basic command execution
|
||||
print("\n--- Test 1: Basic Command Execution ---");
|
||||
let result = run_command("echo hello world");
|
||||
assert_true(result.success, "Command should succeed");
|
||||
assert_true(result.code == 0, "Exit code should be 0");
|
||||
assert_true(result.stdout.contains("hello world"), "Output should contain 'hello world'");
|
||||
print("✓ Basic command execution works");
|
||||
|
||||
// Test 2: Silent command execution
|
||||
print("\n--- Test 2: Silent Command Execution ---");
|
||||
let silent_result = run_silent("echo silent test");
|
||||
assert_true(silent_result.success, "Silent command should succeed");
|
||||
assert_true(silent_result.stdout.contains("silent test"), "Silent output should be captured");
|
||||
print("✓ Silent command execution works");
|
||||
|
||||
// Test 3: Builder pattern
|
||||
print("\n--- Test 3: Builder Pattern ---");
|
||||
let builder_result = run("echo builder pattern").silent().execute();
|
||||
assert_true(builder_result.success, "Builder command should succeed");
|
||||
assert_true(builder_result.stdout.contains("builder pattern"), "Builder output should be captured");
|
||||
print("✓ Builder pattern works");
|
||||
|
||||
// Test 4: Error handling with die=false
|
||||
print("\n--- Test 4: Error Handling (ignore_error) ---");
|
||||
let error_result = run("false").ignore_error().silent().execute();
|
||||
assert_true(!error_result.success, "Command should fail");
|
||||
assert_true(error_result.code != 0, "Exit code should be non-zero");
|
||||
print("✓ Error handling with ignore_error works");
|
||||
|
||||
// Test 5: Multiline script execution
|
||||
print("\n--- Test 5: Multiline Script Execution ---");
|
||||
let script = `
|
||||
echo "Line 1"
|
||||
echo "Line 2"
|
||||
echo "Line 3"
|
||||
`;
|
||||
let script_result = run_command(script);
|
||||
assert_true(script_result.success, "Script should succeed");
|
||||
assert_true(script_result.stdout.contains("Line 1"), "Should contain Line 1");
|
||||
assert_true(script_result.stdout.contains("Line 2"), "Should contain Line 2");
|
||||
assert_true(script_result.stdout.contains("Line 3"), "Should contain Line 3");
|
||||
print("✓ Multiline script execution works");
|
||||
|
||||
// Test 6: Command with arguments
|
||||
print("\n--- Test 6: Command with Arguments ---");
|
||||
let args_result = run_command("echo arg1 arg2 arg3");
|
||||
assert_true(args_result.success, "Command with args should succeed");
|
||||
assert_true(args_result.stdout.contains("arg1 arg2 arg3"), "Should contain all arguments");
|
||||
print("✓ Command with arguments works");
|
||||
|
||||
// Test 7: Builder with logging
|
||||
print("\n--- Test 7: Builder with Logging ---");
|
||||
let log_result = run("echo log test").log().silent().execute();
|
||||
assert_true(log_result.success, "Logged command should succeed");
|
||||
assert_true(log_result.stdout.contains("log test"), "Logged output should be captured");
|
||||
print("✓ Builder with logging works");
|
||||
|
||||
// Test 8: Run with options map
|
||||
print("\n--- Test 8: Run with Options Map ---");
|
||||
let options = #{
|
||||
silent: true,
|
||||
die: false,
|
||||
log: false
|
||||
};
|
||||
let options_result = run("echo options test", options);
|
||||
assert_true(options_result.success, "Options command should succeed");
|
||||
assert_true(options_result.stdout.contains("options test"), "Options output should be captured");
|
||||
print("✓ Run with options map works");
|
||||
|
||||
// Test 9: Complex script with variables
|
||||
print("\n--- Test 9: Complex Script with Variables ---");
|
||||
let var_script = `
|
||||
VAR="test_variable"
|
||||
echo "Variable value: $VAR"
|
||||
`;
|
||||
let var_result = run_command(var_script);
|
||||
assert_true(var_result.success, "Variable script should succeed");
|
||||
assert_true(var_result.stdout.contains("Variable value: test_variable"), "Should expand variables");
|
||||
print("✓ Complex script with variables works");
|
||||
|
||||
// Test 10: Script with conditionals
|
||||
print("\n--- Test 10: Script with Conditionals ---");
|
||||
let cond_script = `
|
||||
if [ "hello" = "hello" ]; then
|
||||
echo "Condition passed"
|
||||
else
|
||||
echo "Condition failed"
|
||||
fi
|
||||
`;
|
||||
let cond_result = run_command(cond_script);
|
||||
assert_true(cond_result.success, "Conditional script should succeed");
|
||||
assert_true(cond_result.stdout.contains("Condition passed"), "Condition should pass");
|
||||
print("✓ Script with conditionals works");
|
||||
|
||||
// Test 11: Builder method chaining
|
||||
print("\n--- Test 11: Builder Method Chaining ---");
|
||||
let chain_result = run("echo chaining test")
|
||||
.silent()
|
||||
.ignore_error()
|
||||
.log()
|
||||
.execute();
|
||||
assert_true(chain_result.success, "Chained command should succeed");
|
||||
assert_true(chain_result.stdout.contains("chaining test"), "Chained output should be captured");
|
||||
print("✓ Builder method chaining works");
|
||||
|
||||
// Test 12: CommandResult properties
|
||||
print("\n--- Test 12: CommandResult Properties ---");
|
||||
let prop_result = run_command("echo property test");
|
||||
assert_true(prop_result.success, "Property test command should succeed");
|
||||
assert_true(prop_result.code == 0, "Exit code property should be 0");
|
||||
assert_true(prop_result.stdout.len() > 0, "Stdout property should not be empty");
|
||||
assert_true(prop_result.stderr.len() >= 0, "Stderr property should exist");
|
||||
print("✓ CommandResult properties work");
|
||||
|
||||
print("\n=== All Command Execution Tests Passed! ===");
|
153
process/tests/rhai/02_process_management.rhai
Normal file
153
process/tests/rhai/02_process_management.rhai
Normal file
@@ -0,0 +1,153 @@
|
||||
// Test script for process management functionality
|
||||
|
||||
print("=== Process Management Tests ===");
|
||||
|
||||
// Test 1: which function with existing command
|
||||
print("\n--- Test 1: Which Function (Existing Command) ---");
|
||||
let echo_path = which("echo");
|
||||
if echo_path != () {
|
||||
assert_true(echo_path.len() > 0, "Echo path should not be empty");
|
||||
print(`✓ which("echo") found at: ${echo_path}`);
|
||||
} else {
|
||||
// Try platform-specific commands
|
||||
let cmd_path = which("cmd");
|
||||
let sh_path = which("sh");
|
||||
assert_true(cmd_path != () || sh_path != (), "Should find either cmd or sh");
|
||||
print("✓ which() function works with platform-specific commands");
|
||||
}
|
||||
|
||||
// Test 2: which function with nonexistent command
|
||||
print("\n--- Test 2: Which Function (Nonexistent Command) ---");
|
||||
let nonexistent = which("nonexistent_command_12345");
|
||||
assert_true(nonexistent == (), "Nonexistent command should return ()");
|
||||
print("✓ which() correctly handles nonexistent commands");
|
||||
|
||||
// Test 3: process_list function
|
||||
print("\n--- Test 3: Process List Function ---");
|
||||
let all_processes = process_list("");
|
||||
assert_true(all_processes.len() > 0, "Should find at least one running process");
|
||||
print(`✓ process_list("") found ${all_processes.len()} processes`);
|
||||
|
||||
// Test 4: process info properties
|
||||
print("\n--- Test 4: Process Info Properties ---");
|
||||
if all_processes.len() > 0 {
|
||||
let first_process = all_processes[0];
|
||||
assert_true(first_process.pid > 0, "Process PID should be positive");
|
||||
assert_true(first_process.name.len() > 0, "Process name should not be empty");
|
||||
assert_true(first_process.memory >= 0.0, "Process memory should be non-negative");
|
||||
assert_true(first_process.cpu >= 0.0, "Process CPU should be non-negative");
|
||||
print(`✓ Process properties: PID=${first_process.pid}, Name=${first_process.name}`);
|
||||
}
|
||||
|
||||
// Test 5: process_list with pattern
|
||||
print("\n--- Test 5: Process List with Pattern ---");
|
||||
if all_processes.len() > 0 {
|
||||
let test_process = all_processes[0];
|
||||
let filtered_processes = process_list(test_process.name);
|
||||
assert_true(filtered_processes.len() >= 1, "Should find at least the test process");
|
||||
|
||||
// Verify all filtered processes contain the pattern
|
||||
for process in filtered_processes {
|
||||
assert_true(process.name.contains(test_process.name), "Filtered process should contain pattern");
|
||||
}
|
||||
print(`✓ process_list("${test_process.name}") found ${filtered_processes.len()} matching processes`);
|
||||
}
|
||||
|
||||
// Test 6: process_list with nonexistent pattern
|
||||
print("\n--- Test 6: Process List with Nonexistent Pattern ---");
|
||||
let empty_list = process_list("nonexistent_process_12345");
|
||||
assert_true(empty_list.len() == 0, "Should find no processes with nonexistent pattern");
|
||||
print("✓ process_list() correctly handles nonexistent patterns");
|
||||
|
||||
// Test 7: kill function with nonexistent process
|
||||
print("\n--- Test 7: Kill Function (Nonexistent Process) ---");
|
||||
let kill_result = kill("nonexistent_process_12345");
|
||||
assert_true(
|
||||
kill_result.contains("No matching processes") || kill_result.contains("Successfully killed"),
|
||||
"Kill should handle nonexistent processes gracefully"
|
||||
);
|
||||
print(`✓ kill("nonexistent_process_12345") result: ${kill_result}`);
|
||||
|
||||
// Test 8: Common system commands detection
|
||||
print("\n--- Test 8: Common System Commands Detection ---");
|
||||
let common_commands = ["echo", "ls", "cat", "grep", "awk", "sed"];
|
||||
let windows_commands = ["cmd", "powershell", "notepad", "tasklist"];
|
||||
|
||||
let found_commands = [];
|
||||
for cmd in common_commands {
|
||||
let path = which(cmd);
|
||||
if path != () {
|
||||
found_commands.push(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
for cmd in windows_commands {
|
||||
let path = which(cmd);
|
||||
if path != () {
|
||||
found_commands.push(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
assert_true(found_commands.len() > 0, "Should find at least one common command");
|
||||
print(`✓ Found common commands: ${found_commands}`);
|
||||
|
||||
// Test 9: Process filtering accuracy
|
||||
print("\n--- Test 9: Process Filtering Accuracy ---");
|
||||
if all_processes.len() > 0 {
|
||||
let test_process = all_processes[0];
|
||||
let filtered = process_list(test_process.name);
|
||||
|
||||
// All filtered processes should contain the pattern
|
||||
let all_match = true;
|
||||
for process in filtered {
|
||||
if !process.name.contains(test_process.name) {
|
||||
all_match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert_true(all_match, "All filtered processes should contain the search pattern");
|
||||
print("✓ Process filtering is accurate");
|
||||
}
|
||||
|
||||
// Test 10: Process management performance
|
||||
print("\n--- Test 10: Process Management Performance ---");
|
||||
let start_time = timestamp();
|
||||
let perf_processes = process_list("");
|
||||
let end_time = timestamp();
|
||||
let duration = end_time - start_time;
|
||||
|
||||
assert_true(duration < 5000, "Process listing should complete within 5 seconds");
|
||||
assert_true(perf_processes.len() > 0, "Performance test should still return processes");
|
||||
print(`✓ process_list() completed in ${duration}ms`);
|
||||
|
||||
// Test 11: which command performance
|
||||
print("\n--- Test 11: Which Command Performance ---");
|
||||
let which_start = timestamp();
|
||||
let which_result = which("echo");
|
||||
let which_end = timestamp();
|
||||
let which_duration = which_end - which_start;
|
||||
|
||||
assert_true(which_duration < 1000, "which() should complete within 1 second");
|
||||
print(`✓ which("echo") completed in ${which_duration}ms`);
|
||||
|
||||
// Test 12: Cross-platform process operations
|
||||
print("\n--- Test 12: Cross-Platform Process Operations ---");
|
||||
let platform_specific_found = false;
|
||||
|
||||
// Try Windows-specific
|
||||
let cmd_found = which("cmd");
|
||||
if cmd_found != () {
|
||||
platform_specific_found = true;
|
||||
print("✓ Windows platform detected (cmd found)");
|
||||
}
|
||||
|
||||
// Try Unix-specific
|
||||
let sh_found = which("sh");
|
||||
if sh_found != () {
|
||||
platform_specific_found = true;
|
||||
print("✓ Unix-like platform detected (sh found)");
|
||||
}
|
||||
|
||||
assert_true(platform_specific_found, "Should detect platform-specific commands");
|
||||
|
||||
print("\n=== All Process Management Tests Passed! ===");
|
167
process/tests/rhai/03_error_handling.rhai
Normal file
167
process/tests/rhai/03_error_handling.rhai
Normal file
@@ -0,0 +1,167 @@
|
||||
// Test script for process error handling functionality
|
||||
|
||||
print("=== Process Error Handling Tests ===");
|
||||
|
||||
// Test 1: Command execution error handling
|
||||
print("\n--- Test 1: Command Execution Error Handling ---");
|
||||
try {
|
||||
let result = run_command("nonexistent_command_12345");
|
||||
assert_true(false, "Should have thrown an error for nonexistent command");
|
||||
} catch(e) {
|
||||
assert_true(true, "Correctly caught error for nonexistent command");
|
||||
print("✓ Command execution error handling works");
|
||||
}
|
||||
|
||||
// Test 2: Silent error handling with ignore_error
|
||||
print("\n--- Test 2: Silent Error Handling with ignore_error ---");
|
||||
let error_result = run("false").ignore_error().silent().execute();
|
||||
assert_true(!error_result.success, "Command should fail");
|
||||
assert_true(error_result.code != 0, "Exit code should be non-zero");
|
||||
print("✓ Silent error handling with ignore_error works");
|
||||
|
||||
// Test 3: Process management error handling
|
||||
print("\n--- Test 3: Process Management Error Handling ---");
|
||||
try {
|
||||
let result = process_get("nonexistent_process_12345");
|
||||
assert_true(false, "Should have thrown an error for nonexistent process");
|
||||
} catch(e) {
|
||||
assert_true(true, "Correctly caught error for nonexistent process");
|
||||
print("✓ Process management error handling works");
|
||||
}
|
||||
|
||||
// Test 4: Script execution error handling
|
||||
print("\n--- Test 4: Script Execution Error Handling ---");
|
||||
let error_script = `
|
||||
echo "Before error"
|
||||
false
|
||||
echo "After error"
|
||||
`;
|
||||
|
||||
try {
|
||||
let result = run_command(error_script);
|
||||
assert_true(false, "Should have thrown an error for failing script");
|
||||
} catch(e) {
|
||||
assert_true(true, "Correctly caught error for failing script");
|
||||
print("✓ Script execution error handling works");
|
||||
}
|
||||
|
||||
// Test 5: Error handling with die=false in options
|
||||
print("\n--- Test 5: Error Handling with die=false in Options ---");
|
||||
let options = #{
|
||||
silent: true,
|
||||
die: false,
|
||||
log: false
|
||||
};
|
||||
let no_die_result = run("false", options);
|
||||
assert_true(!no_die_result.success, "Command should fail but not throw");
|
||||
assert_true(no_die_result.code != 0, "Exit code should be non-zero");
|
||||
print("✓ Error handling with die=false in options works");
|
||||
|
||||
// Test 6: Builder pattern error handling
|
||||
print("\n--- Test 6: Builder Pattern Error Handling ---");
|
||||
try {
|
||||
let result = run("nonexistent_command_12345").silent().execute();
|
||||
assert_true(false, "Should have thrown an error for nonexistent command in builder");
|
||||
} catch(e) {
|
||||
assert_true(true, "Correctly caught error for nonexistent command in builder");
|
||||
print("✓ Builder pattern error handling works");
|
||||
}
|
||||
|
||||
// Test 7: Multiple error conditions
|
||||
print("\n--- Test 7: Multiple Error Conditions ---");
|
||||
let error_conditions = [
|
||||
"nonexistent_command_12345",
|
||||
"false",
|
||||
"exit 1"
|
||||
];
|
||||
|
||||
for cmd in error_conditions {
|
||||
try {
|
||||
let result = run(cmd).silent().execute();
|
||||
assert_true(false, `Should have thrown an error for: ${cmd}`);
|
||||
} catch(e) {
|
||||
// Expected behavior
|
||||
}
|
||||
}
|
||||
print("✓ Multiple error conditions handled correctly");
|
||||
|
||||
// Test 8: Error recovery with ignore_error
|
||||
print("\n--- Test 8: Error Recovery with ignore_error ---");
|
||||
let recovery_script = `
|
||||
echo "Starting script"
|
||||
false
|
||||
echo "This should not execute"
|
||||
`;
|
||||
|
||||
let recovery_result = run(recovery_script).ignore_error().silent().execute();
|
||||
assert_true(!recovery_result.success, "Script should fail");
|
||||
assert_true(recovery_result.stdout.contains("Starting script"), "Should capture output before error");
|
||||
print("✓ Error recovery with ignore_error works");
|
||||
|
||||
// Test 9: Nested error handling
|
||||
print("\n--- Test 9: Nested Error Handling ---");
|
||||
try {
|
||||
try {
|
||||
let result = run_command("nonexistent_command_12345");
|
||||
assert_true(false, "Inner try should fail");
|
||||
} catch(inner_e) {
|
||||
// Re-throw to test outer catch
|
||||
throw inner_e;
|
||||
}
|
||||
assert_true(false, "Outer try should fail");
|
||||
} catch(outer_e) {
|
||||
assert_true(true, "Nested error handling works");
|
||||
print("✓ Nested error handling works");
|
||||
}
|
||||
|
||||
// Test 10: Error message content validation
|
||||
print("\n--- Test 10: Error Message Content Validation ---");
|
||||
try {
|
||||
let result = process_get("nonexistent_process_12345");
|
||||
assert_true(false, "Should have thrown an error");
|
||||
} catch(e) {
|
||||
let error_msg = `${e}`;
|
||||
assert_true(error_msg.len() > 0, "Error message should not be empty");
|
||||
print(`✓ Error message content: ${error_msg}`);
|
||||
}
|
||||
|
||||
// Test 11: Graceful degradation
|
||||
print("\n--- Test 11: Graceful Degradation ---");
|
||||
let graceful_commands = [
|
||||
"echo 'fallback test'",
|
||||
"printf 'fallback test'",
|
||||
"print 'fallback test'"
|
||||
];
|
||||
|
||||
let graceful_success = false;
|
||||
for cmd in graceful_commands {
|
||||
try {
|
||||
let result = run_command(cmd);
|
||||
if result.success {
|
||||
graceful_success = true;
|
||||
break;
|
||||
}
|
||||
} catch(e) {
|
||||
// Try next command
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
assert_true(graceful_success, "Should find at least one working command for graceful degradation");
|
||||
print("✓ Graceful degradation works");
|
||||
|
||||
// Test 12: Error handling performance
|
||||
print("\n--- Test 12: Error Handling Performance ---");
|
||||
let error_start = timestamp();
|
||||
try {
|
||||
let result = run_command("nonexistent_command_12345");
|
||||
} catch(e) {
|
||||
// Expected
|
||||
}
|
||||
let error_end = timestamp();
|
||||
let error_duration = error_end - error_start;
|
||||
|
||||
assert_true(error_duration < 5000, "Error handling should be fast (< 5 seconds)");
|
||||
print(`✓ Error handling completed in ${error_duration}ms`);
|
||||
|
||||
print("\n=== All Error Handling Tests Passed! ===");
|
326
process/tests/rhai/04_real_world_scenarios.rhai
Normal file
326
process/tests/rhai/04_real_world_scenarios.rhai
Normal file
@@ -0,0 +1,326 @@
|
||||
// Test script for real-world process scenarios
|
||||
|
||||
print("=== Real-World Process Scenarios Tests ===");
|
||||
|
||||
// Test 1: System information gathering
|
||||
print("\n--- Test 1: System Information Gathering ---");
|
||||
let system_info = #{};
|
||||
|
||||
// Get current user
|
||||
try {
|
||||
let whoami_result = run_command("whoami");
|
||||
if whoami_result.success {
|
||||
system_info.user = whoami_result.stdout.trim();
|
||||
print(`✓ Current user: ${system_info.user}`);
|
||||
}
|
||||
} catch(e) {
|
||||
print("⚠ whoami command not available");
|
||||
}
|
||||
|
||||
// Get current directory
|
||||
try {
|
||||
let pwd_result = run_command("pwd");
|
||||
if pwd_result.success {
|
||||
system_info.pwd = pwd_result.stdout.trim();
|
||||
print(`✓ Current directory: ${system_info.pwd}`);
|
||||
}
|
||||
} catch(e) {
|
||||
// Try Windows alternative
|
||||
try {
|
||||
let cd_result = run_command("cd");
|
||||
if cd_result.success {
|
||||
system_info.pwd = cd_result.stdout.trim();
|
||||
print(`✓ Current directory (Windows): ${system_info.pwd}`);
|
||||
}
|
||||
} catch(e2) {
|
||||
print("⚠ pwd/cd commands not available");
|
||||
}
|
||||
}
|
||||
|
||||
assert_true(system_info.len() > 0, "Should gather at least some system information");
|
||||
|
||||
// Test 2: File system operations
|
||||
print("\n--- Test 2: File System Operations ---");
|
||||
let temp_file = "/tmp/sal_process_test.txt";
|
||||
let temp_content = "SAL Process Test Content";
|
||||
|
||||
// Create a test file
|
||||
let create_script = `
|
||||
echo "${temp_content}" > ${temp_file}
|
||||
`;
|
||||
|
||||
try {
|
||||
let create_result = run_command(create_script);
|
||||
if create_result.success {
|
||||
print("✓ Test file created successfully");
|
||||
|
||||
// Read the file back
|
||||
let read_result = run_command(`cat ${temp_file}`);
|
||||
if read_result.success {
|
||||
assert_true(read_result.stdout.contains(temp_content), "File content should match");
|
||||
print("✓ Test file read successfully");
|
||||
}
|
||||
|
||||
// Clean up
|
||||
let cleanup_result = run_command(`rm -f ${temp_file}`);
|
||||
if cleanup_result.success {
|
||||
print("✓ Test file cleaned up successfully");
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
print("⚠ File system operations not available on this platform");
|
||||
}
|
||||
|
||||
// Test 3: Process monitoring workflow
|
||||
print("\n--- Test 3: Process Monitoring Workflow ---");
|
||||
let monitoring_workflow = || {
|
||||
// Get all processes
|
||||
let all_processes = process_list("");
|
||||
assert_true(all_processes.len() > 0, "Should find running processes");
|
||||
|
||||
// Find processes with common names
|
||||
let common_patterns = ["init", "kernel", "system", "explorer", "winlogon"];
|
||||
let found_patterns = [];
|
||||
|
||||
for pattern in common_patterns {
|
||||
let matches = process_list(pattern);
|
||||
if matches.len() > 0 {
|
||||
found_patterns.push(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
print(`✓ Process monitoring found patterns: ${found_patterns}`);
|
||||
return found_patterns.len() > 0;
|
||||
};
|
||||
|
||||
assert_true(monitoring_workflow(), "Process monitoring workflow should succeed");
|
||||
|
||||
// Test 4: Command availability checking
|
||||
print("\n--- Test 4: Command Availability Checking ---");
|
||||
let essential_commands = ["echo"];
|
||||
let optional_commands = ["git", "curl", "wget", "python", "node", "java"];
|
||||
|
||||
let available_commands = [];
|
||||
let missing_commands = [];
|
||||
|
||||
// Check essential commands
|
||||
for cmd in essential_commands {
|
||||
let path = which(cmd);
|
||||
if path != () {
|
||||
available_commands.push(cmd);
|
||||
} else {
|
||||
missing_commands.push(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
// Check optional commands
|
||||
for cmd in optional_commands {
|
||||
let path = which(cmd);
|
||||
if path != () {
|
||||
available_commands.push(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
assert_true(missing_commands.len() == 0, "All essential commands should be available");
|
||||
print(`✓ Available commands: ${available_commands}`);
|
||||
print(`✓ Command availability check completed`);
|
||||
|
||||
// Test 5: Batch processing simulation
|
||||
print("\n--- Test 5: Batch Processing Simulation ---");
|
||||
let batch_commands = [
|
||||
"echo 'Processing item 1'",
|
||||
"echo 'Processing item 2'",
|
||||
"echo 'Processing item 3'"
|
||||
];
|
||||
|
||||
let batch_results = [];
|
||||
let batch_success = true;
|
||||
|
||||
for cmd in batch_commands {
|
||||
try {
|
||||
let result = run(cmd).silent().execute();
|
||||
batch_results.push(result);
|
||||
if !result.success {
|
||||
batch_success = false;
|
||||
}
|
||||
} catch(e) {
|
||||
batch_success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert_true(batch_success, "Batch processing should succeed");
|
||||
assert_true(batch_results.len() == batch_commands.len(), "Should process all batch items");
|
||||
print(`✓ Batch processing completed: ${batch_results.len()} items`);
|
||||
|
||||
// Test 6: Environment variable handling
|
||||
print("\n--- Test 6: Environment Variable Handling ---");
|
||||
let env_test_script = `
|
||||
export TEST_VAR="test_value"
|
||||
echo "TEST_VAR=$TEST_VAR"
|
||||
`;
|
||||
|
||||
try {
|
||||
let env_result = run_command(env_test_script);
|
||||
if env_result.success {
|
||||
assert_true(env_result.stdout.contains("TEST_VAR=test_value"), "Environment variable should be set");
|
||||
print("✓ Environment variable handling works");
|
||||
}
|
||||
} catch(e) {
|
||||
print("⚠ Environment variable test not available");
|
||||
}
|
||||
|
||||
// Test 7: Pipeline simulation
|
||||
print("\n--- Test 7: Pipeline Simulation ---");
|
||||
let pipeline_script = `
|
||||
echo "line1
|
||||
line2
|
||||
line3" | grep "line2"
|
||||
`;
|
||||
|
||||
try {
|
||||
let pipeline_result = run_command(pipeline_script);
|
||||
if pipeline_result.success {
|
||||
assert_true(pipeline_result.stdout.contains("line2"), "Pipeline should filter correctly");
|
||||
print("✓ Pipeline simulation works");
|
||||
}
|
||||
} catch(e) {
|
||||
print("⚠ Pipeline simulation not available");
|
||||
}
|
||||
|
||||
// Test 8: Error recovery workflow
|
||||
print("\n--- Test 8: Error Recovery Workflow ---");
|
||||
let recovery_workflow = || {
|
||||
let primary_cmd = "nonexistent_primary_command";
|
||||
let fallback_cmd = "echo 'fallback executed'";
|
||||
|
||||
// Try primary command
|
||||
try {
|
||||
let primary_result = run_command(primary_cmd);
|
||||
return primary_result.success;
|
||||
} catch(e) {
|
||||
// Primary failed, try fallback
|
||||
try {
|
||||
let fallback_result = run_command(fallback_cmd);
|
||||
return fallback_result.success && fallback_result.stdout.contains("fallback executed");
|
||||
} catch(e2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
assert_true(recovery_workflow(), "Error recovery workflow should succeed");
|
||||
print("✓ Error recovery workflow works");
|
||||
|
||||
// Test 9: Resource monitoring
|
||||
print("\n--- Test 9: Resource Monitoring ---");
|
||||
let resource_monitoring = || {
|
||||
let start_time = timestamp();
|
||||
|
||||
// Simulate resource-intensive operation
|
||||
let intensive_script = `
|
||||
for i in $(seq 1 10); do
|
||||
echo "Processing $i"
|
||||
done
|
||||
`;
|
||||
|
||||
try {
|
||||
let result = run(intensive_script).silent().execute();
|
||||
let end_time = timestamp();
|
||||
let duration = end_time - start_time;
|
||||
|
||||
print(`✓ Resource monitoring: operation took ${duration}ms`);
|
||||
return result.success && duration < 10000; // Should complete within 10 seconds
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
assert_true(resource_monitoring(), "Resource monitoring should work");
|
||||
|
||||
// Test 10: Cross-platform compatibility
|
||||
print("\n--- Test 10: Cross-Platform Compatibility ---");
|
||||
let cross_platform_test = || {
|
||||
// Test basic commands that should work everywhere
|
||||
let basic_commands = ["echo hello"];
|
||||
|
||||
for cmd in basic_commands {
|
||||
try {
|
||||
let result = run_command(cmd);
|
||||
if !result.success {
|
||||
return false;
|
||||
}
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Test platform detection
|
||||
let windows_detected = which("cmd") != ();
|
||||
let unix_detected = which("sh") != ();
|
||||
|
||||
return windows_detected || unix_detected;
|
||||
};
|
||||
|
||||
assert_true(cross_platform_test(), "Cross-platform compatibility should work");
|
||||
print("✓ Cross-platform compatibility verified");
|
||||
|
||||
// Test 11: Complex workflow integration
|
||||
print("\n--- Test 11: Complex Workflow Integration ---");
|
||||
let complex_workflow = || {
|
||||
// Step 1: Check prerequisites
|
||||
let echo_available = which("echo") != ();
|
||||
if !echo_available {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 2: Execute main task
|
||||
let main_result = run("echo 'Complex workflow step'").silent().execute();
|
||||
if !main_result.success {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 3: Verify results
|
||||
let verify_result = run("echo 'Verification step'").silent().execute();
|
||||
if !verify_result.success {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 4: Cleanup (always succeeds)
|
||||
let cleanup_result = run("echo 'Cleanup step'").ignore_error().silent().execute();
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
assert_true(complex_workflow(), "Complex workflow integration should succeed");
|
||||
print("✓ Complex workflow integration works");
|
||||
|
||||
// Test 12: Performance under load
|
||||
print("\n--- Test 12: Performance Under Load ---");
|
||||
let performance_test = || {
|
||||
let start_time = timestamp();
|
||||
let iterations = 5;
|
||||
let success_count = 0;
|
||||
|
||||
for i in range(0, iterations) {
|
||||
try {
|
||||
let result = run(`echo "Iteration ${i}"`).silent().execute();
|
||||
if result.success {
|
||||
success_count += 1;
|
||||
}
|
||||
} catch(e) {
|
||||
// Continue with next iteration
|
||||
}
|
||||
}
|
||||
|
||||
let end_time = timestamp();
|
||||
let duration = end_time - start_time;
|
||||
let avg_time = duration / iterations;
|
||||
|
||||
print(`✓ Performance test: ${success_count}/${iterations} succeeded, avg ${avg_time}ms per operation`);
|
||||
return success_count == iterations && avg_time < 1000; // Each operation should be < 1 second
|
||||
};
|
||||
|
||||
assert_true(performance_test(), "Performance under load should be acceptable");
|
||||
|
||||
print("\n=== All Real-World Scenarios Tests Passed! ===");
|
321
process/tests/rhai_tests.rs
Normal file
321
process/tests/rhai_tests.rs
Normal file
@@ -0,0 +1,321 @@
|
||||
use rhai::Engine;
|
||||
use sal_process::rhai::register_process_module;
|
||||
|
||||
fn create_test_engine() -> Engine {
|
||||
let mut engine = Engine::new();
|
||||
register_process_module(&mut engine).unwrap();
|
||||
engine
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rhai_run_command() {
|
||||
let engine = create_test_engine();
|
||||
|
||||
let script = r#"
|
||||
let result = run_command("echo hello");
|
||||
result.success && result.stdout.contains("hello")
|
||||
"#;
|
||||
|
||||
let result: bool = engine.eval(script).unwrap();
|
||||
assert!(result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rhai_run_silent() {
|
||||
let engine = create_test_engine();
|
||||
|
||||
let script = r#"
|
||||
let result = run_silent("echo silent test");
|
||||
result.success && result.stdout.contains("silent test")
|
||||
"#;
|
||||
|
||||
let result: bool = engine.eval(script).unwrap();
|
||||
assert!(result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rhai_run_builder_pattern() {
|
||||
let engine = create_test_engine();
|
||||
|
||||
let script = r#"
|
||||
let result = run("echo builder test").silent().execute();
|
||||
result.success && result.stdout.contains("builder test")
|
||||
"#;
|
||||
|
||||
let result: bool = engine.eval(script).unwrap();
|
||||
assert!(result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rhai_run_builder_ignore_error() {
|
||||
let engine = create_test_engine();
|
||||
|
||||
let script = r#"
|
||||
let result = run("false").ignore_error().silent().execute();
|
||||
!result.success
|
||||
"#;
|
||||
|
||||
let result: bool = engine.eval(script).unwrap();
|
||||
assert!(result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rhai_run_builder_with_log() {
|
||||
let engine = create_test_engine();
|
||||
|
||||
let script = r#"
|
||||
let result = run("echo log test").log().silent().execute();
|
||||
result.success && result.stdout.contains("log test")
|
||||
"#;
|
||||
|
||||
let result: bool = engine.eval(script).unwrap();
|
||||
assert!(result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rhai_which_function() {
|
||||
let engine = create_test_engine();
|
||||
|
||||
// Test with a command that should exist
|
||||
#[cfg(target_os = "windows")]
|
||||
let script = r#"
|
||||
let path = which("cmd");
|
||||
path != () && path.len() > 0
|
||||
"#;
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let script = r#"
|
||||
let path = which("sh");
|
||||
path != () && path.len() > 0
|
||||
"#;
|
||||
|
||||
let result: bool = engine.eval(script).unwrap();
|
||||
assert!(result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rhai_which_nonexistent() {
|
||||
let engine = create_test_engine();
|
||||
|
||||
let script = r#"
|
||||
let path = which("nonexistent_command_12345");
|
||||
path == ()
|
||||
"#;
|
||||
|
||||
let result: bool = engine.eval(script).unwrap();
|
||||
assert!(result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rhai_process_list() {
|
||||
let engine = create_test_engine();
|
||||
|
||||
let script = r#"
|
||||
let processes = process_list("");
|
||||
processes.len() > 0
|
||||
"#;
|
||||
|
||||
let result: bool = engine.eval(script).unwrap();
|
||||
assert!(result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rhai_process_list_with_pattern() {
|
||||
let engine = create_test_engine();
|
||||
|
||||
let script = r#"
|
||||
let all_processes = process_list("");
|
||||
if all_processes.len() > 0 {
|
||||
let first_process = all_processes[0];
|
||||
let filtered = process_list(first_process.name);
|
||||
filtered.len() >= 1
|
||||
} else {
|
||||
false
|
||||
}
|
||||
"#;
|
||||
|
||||
let result: bool = engine.eval(script).unwrap();
|
||||
assert!(result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rhai_process_info_properties() {
|
||||
let engine = create_test_engine();
|
||||
|
||||
let script = r#"
|
||||
let processes = process_list("");
|
||||
if processes.len() > 0 {
|
||||
let process = processes[0];
|
||||
process.pid > 0 && process.name.len() > 0
|
||||
} else {
|
||||
false
|
||||
}
|
||||
"#;
|
||||
|
||||
let result: bool = engine.eval(script).unwrap();
|
||||
assert!(result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rhai_command_result_properties() {
|
||||
let engine = create_test_engine();
|
||||
|
||||
let script = r#"
|
||||
let result = run_command("echo test");
|
||||
result.success && result.stdout.contains("test")
|
||||
"#;
|
||||
|
||||
let result: bool = engine.eval(script).unwrap();
|
||||
assert!(result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rhai_kill_nonexistent() {
|
||||
let engine = create_test_engine();
|
||||
|
||||
let script = r#"
|
||||
let result = kill("nonexistent_process_12345");
|
||||
result.contains("No matching processes") || result.contains("Successfully killed")
|
||||
"#;
|
||||
|
||||
let result: bool = engine.eval(script).unwrap();
|
||||
assert!(result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rhai_run_with_options() {
|
||||
let engine = create_test_engine();
|
||||
|
||||
let script = r#"
|
||||
let options = #{
|
||||
silent: true,
|
||||
die: false,
|
||||
log: false
|
||||
};
|
||||
let result = run("echo options test", options);
|
||||
result.success && result.stdout.contains("options test")
|
||||
"#;
|
||||
|
||||
let result: bool = engine.eval(script).unwrap();
|
||||
assert!(result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rhai_run_multiline_script() {
|
||||
let engine = create_test_engine();
|
||||
|
||||
let script = r#"
|
||||
let bash_script = `
|
||||
echo "Line 1"
|
||||
echo "Line 2"
|
||||
echo "Line 3"
|
||||
`;
|
||||
let result = run_command(bash_script);
|
||||
result.success &&
|
||||
result.stdout.contains("Line 1") &&
|
||||
result.stdout.contains("Line 2") &&
|
||||
result.stdout.contains("Line 3")
|
||||
"#;
|
||||
|
||||
let result: bool = engine.eval(script).unwrap();
|
||||
assert!(result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rhai_error_handling() {
|
||||
let engine = create_test_engine();
|
||||
|
||||
// Test that errors are properly converted to Rhai errors
|
||||
let script = r#"
|
||||
let error_occurred = false;
|
||||
try {
|
||||
run_command("nonexistent_command_12345");
|
||||
} catch(e) {
|
||||
error_occurred = true;
|
||||
}
|
||||
error_occurred
|
||||
"#;
|
||||
|
||||
let result: bool = engine.eval(script).unwrap();
|
||||
assert!(result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rhai_process_get_error_handling() {
|
||||
let engine = create_test_engine();
|
||||
|
||||
let script = r#"
|
||||
let error_occurred = false;
|
||||
try {
|
||||
process_get("nonexistent_process_12345");
|
||||
} catch(e) {
|
||||
error_occurred = true;
|
||||
}
|
||||
error_occurred
|
||||
"#;
|
||||
|
||||
let result: bool = engine.eval(script).unwrap();
|
||||
assert!(result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rhai_builder_chaining() {
|
||||
let engine = create_test_engine();
|
||||
|
||||
let script = r#"
|
||||
let result = run("echo chaining")
|
||||
.silent()
|
||||
.ignore_error()
|
||||
.log()
|
||||
.execute();
|
||||
result.success && result.stdout.contains("chaining")
|
||||
"#;
|
||||
|
||||
let result: bool = engine.eval(script).unwrap();
|
||||
assert!(result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rhai_cross_platform_commands() {
|
||||
let engine = create_test_engine();
|
||||
|
||||
// Test platform-specific commands
|
||||
#[cfg(target_os = "windows")]
|
||||
let script = r#"
|
||||
let result = run_command("echo Windows test");
|
||||
result.success && result.stdout.contains("Windows test")
|
||||
"#;
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let script = r#"
|
||||
let result = run_command("echo Unix test");
|
||||
result.success && result.stdout.contains("Unix test")
|
||||
"#;
|
||||
|
||||
let result: bool = engine.eval(script).unwrap();
|
||||
assert!(result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rhai_complex_workflow() {
|
||||
let engine = create_test_engine();
|
||||
|
||||
let script = r#"
|
||||
// Test a complex workflow combining multiple functions
|
||||
let echo_path = which("echo");
|
||||
if echo_path == () {
|
||||
false
|
||||
} else {
|
||||
let result = run("echo workflow test").silent().execute();
|
||||
if !result.success {
|
||||
false
|
||||
} else {
|
||||
let processes = process_list("");
|
||||
processes.len() > 0
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let result: bool = engine.eval(script).unwrap();
|
||||
assert!(result);
|
||||
}
|
251
process/tests/run_tests.rs
Normal file
251
process/tests/run_tests.rs
Normal file
@@ -0,0 +1,251 @@
|
||||
use sal_process::{run, run_command, run_silent, RunError};
|
||||
use std::env;
|
||||
|
||||
#[test]
|
||||
fn test_run_simple_command() {
|
||||
let result = run_command("echo hello").unwrap();
|
||||
assert!(result.success);
|
||||
assert_eq!(result.code, 0);
|
||||
assert!(result.stdout.contains("hello"));
|
||||
assert!(result.stderr.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_command_with_args() {
|
||||
let result = run_command("echo hello world").unwrap();
|
||||
assert!(result.success);
|
||||
assert_eq!(result.code, 0);
|
||||
assert!(result.stdout.contains("hello world"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_silent() {
|
||||
let result = run_silent("echo silent test").unwrap();
|
||||
assert!(result.success);
|
||||
assert_eq!(result.code, 0);
|
||||
assert!(result.stdout.contains("silent test"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_builder_pattern() {
|
||||
let result = run("echo builder test").silent(true).execute().unwrap();
|
||||
|
||||
assert!(result.success);
|
||||
assert_eq!(result.code, 0);
|
||||
assert!(result.stdout.contains("builder test"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_builder_die_false() {
|
||||
let result = run("false") // Command that always fails
|
||||
.die(false)
|
||||
.silent(true)
|
||||
.execute()
|
||||
.unwrap();
|
||||
|
||||
assert!(!result.success);
|
||||
assert_ne!(result.code, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_builder_die_true() {
|
||||
// Use a command that will definitely fail
|
||||
let result = run("exit 1") // Script that always fails
|
||||
.die(true)
|
||||
.silent(true)
|
||||
.execute();
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_multiline_script() {
|
||||
let script = r#"
|
||||
echo "Line 1"
|
||||
echo "Line 2"
|
||||
echo "Line 3"
|
||||
"#;
|
||||
|
||||
let result = run_command(script).unwrap();
|
||||
assert!(result.success);
|
||||
assert_eq!(result.code, 0);
|
||||
assert!(result.stdout.contains("Line 1"));
|
||||
assert!(result.stdout.contains("Line 2"));
|
||||
assert!(result.stdout.contains("Line 3"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_script_with_shebang() {
|
||||
let script = r#"#!/bin/bash
|
||||
echo "Script with shebang"
|
||||
exit 0
|
||||
"#;
|
||||
|
||||
let result = run_command(script).unwrap();
|
||||
assert!(result.success);
|
||||
assert_eq!(result.code, 0);
|
||||
assert!(result.stdout.contains("Script with shebang"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_script_error_handling() {
|
||||
let script = r#"
|
||||
echo "Before error"
|
||||
false
|
||||
echo "After error"
|
||||
"#;
|
||||
|
||||
let result = run(script).silent(true).execute();
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_empty_command() {
|
||||
let result = run_command("");
|
||||
assert!(result.is_err());
|
||||
match result.unwrap_err() {
|
||||
RunError::EmptyCommand => {}
|
||||
_ => panic!("Expected EmptyCommand error"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_nonexistent_command() {
|
||||
let result = run("nonexistent_command_12345").silent(true).execute();
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_with_environment_variables() {
|
||||
env::set_var("TEST_VAR", "test_value");
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
let script = "echo %TEST_VAR%";
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let script = r#"
|
||||
export TEST_VAR="test_value"
|
||||
echo $TEST_VAR
|
||||
"#;
|
||||
|
||||
let result = run_command(script).unwrap();
|
||||
assert!(result.success);
|
||||
assert!(result.stdout.contains("test_value"));
|
||||
|
||||
env::remove_var("TEST_VAR");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_with_working_directory() {
|
||||
// Test that commands run in the current working directory
|
||||
let result = run_command("pwd").unwrap();
|
||||
assert!(result.success);
|
||||
assert!(!result.stdout.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_command_result_properties() {
|
||||
let result = run_command("echo test").unwrap();
|
||||
|
||||
// Test all CommandResult properties
|
||||
assert!(!result.stdout.is_empty());
|
||||
assert!(result.stderr.is_empty());
|
||||
assert!(result.success);
|
||||
assert_eq!(result.code, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_builder_log_option() {
|
||||
// Test that log option doesn't cause errors
|
||||
let result = run("echo log test")
|
||||
.log(true)
|
||||
.silent(true)
|
||||
.execute()
|
||||
.unwrap();
|
||||
|
||||
assert!(result.success);
|
||||
assert!(result.stdout.contains("log test"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_cross_platform_commands() {
|
||||
// Test commands that work on all platforms
|
||||
|
||||
// Test echo command
|
||||
let result = run_command("echo cross-platform").unwrap();
|
||||
assert!(result.success);
|
||||
assert!(result.stdout.contains("cross-platform"));
|
||||
|
||||
// Test basic shell operations
|
||||
#[cfg(target_os = "windows")]
|
||||
let result = run_command("dir").unwrap();
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let result = run_command("ls").unwrap();
|
||||
|
||||
assert!(result.success);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_script_with_variables() {
|
||||
let script = r#"
|
||||
VAR="test_variable"
|
||||
echo "Variable value: $VAR"
|
||||
"#;
|
||||
|
||||
let result = run_command(script).unwrap();
|
||||
assert!(result.success);
|
||||
assert!(result.stdout.contains("Variable value: test_variable"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_script_with_conditionals() {
|
||||
let script = r#"
|
||||
if [ "hello" = "hello" ]; then
|
||||
echo "Condition passed"
|
||||
else
|
||||
echo "Condition failed"
|
||||
fi
|
||||
"#;
|
||||
|
||||
let result = run_command(script).unwrap();
|
||||
assert!(result.success);
|
||||
assert!(result.stdout.contains("Condition passed"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_script_with_loops() {
|
||||
let script = r#"
|
||||
for i in 1 2 3; do
|
||||
echo "Number: $i"
|
||||
done
|
||||
"#;
|
||||
|
||||
let result = run_command(script).unwrap();
|
||||
assert!(result.success);
|
||||
assert!(result.stdout.contains("Number: 1"));
|
||||
assert!(result.stdout.contains("Number: 2"));
|
||||
assert!(result.stdout.contains("Number: 3"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_with_stderr_output() {
|
||||
// Test that stderr field exists and can be accessed
|
||||
let result = run_command("echo test").unwrap();
|
||||
assert!(result.success);
|
||||
// Just verify that stderr field exists and is accessible
|
||||
let _stderr_len = result.stderr.len(); // This verifies stderr field exists
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_builder_chaining() {
|
||||
let result = run("echo chaining test")
|
||||
.silent(true)
|
||||
.die(true)
|
||||
.log(false)
|
||||
.execute()
|
||||
.unwrap();
|
||||
|
||||
assert!(result.success);
|
||||
assert!(result.stdout.contains("chaining test"));
|
||||
}
|
Reference in New Issue
Block a user