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.
279 lines
7.7 KiB
Rust
279 lines
7.7 KiB
Rust
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());
|
|
}
|