297 lines
7.8 KiB
Rust
297 lines
7.8 KiB
Rust
//! Integration tests for terminal operations.
|
|
|
|
use dirigent_tools::config::TerminalConfig;
|
|
use dirigent_tools::terminal::{
|
|
create_terminal, get_terminal_output, kill_terminal, release_terminal,
|
|
wait_for_terminal_exit, CreateTerminalRequest, KillTerminalCommandRequest,
|
|
ReleaseTerminalRequest, TerminalOutputRequest, WaitForTerminalExitRequest,
|
|
};
|
|
|
|
#[tokio::test]
|
|
async fn test_terminal_echo_command() {
|
|
let config = TerminalConfig {
|
|
enabled: true,
|
|
default_cwd: Some(std::env::current_dir().unwrap()),
|
|
env_allowlist: vec![],
|
|
command_blocklist: vec![],
|
|
output_byte_limit: 10_000,
|
|
max_runtime_secs: 30,
|
|
};
|
|
|
|
// Create terminal with echo command
|
|
#[cfg(windows)]
|
|
let request = CreateTerminalRequest {
|
|
command: "cmd".to_string(),
|
|
args: vec!["/C".to_string(), "echo".to_string(), "Hello World".to_string()],
|
|
cwd: None,
|
|
env: None,
|
|
output_byte_limit: None,
|
|
};
|
|
|
|
#[cfg(not(windows))]
|
|
let request = CreateTerminalRequest {
|
|
command: "echo".to_string(),
|
|
args: vec!["Hello World".to_string()],
|
|
cwd: None,
|
|
env: None,
|
|
output_byte_limit: None,
|
|
};
|
|
|
|
let create_response = create_terminal(request, &config).await.unwrap();
|
|
let terminal_id = create_response.terminal_id;
|
|
|
|
// Wait for command to complete
|
|
tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
|
|
|
|
// Get output
|
|
let output_response = get_terminal_output(
|
|
TerminalOutputRequest {
|
|
terminal_id: terminal_id.clone(),
|
|
},
|
|
&config,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert!(output_response.output.contains("Hello World"));
|
|
|
|
// Release terminal
|
|
let _ = release_terminal(
|
|
ReleaseTerminalRequest {
|
|
terminal_id: terminal_id.clone(),
|
|
},
|
|
&config,
|
|
)
|
|
.await;
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_terminal_wait_for_exit() {
|
|
let config = TerminalConfig {
|
|
enabled: true,
|
|
default_cwd: Some(std::env::current_dir().unwrap()),
|
|
env_allowlist: vec![],
|
|
command_blocklist: vec![],
|
|
output_byte_limit: 10_000,
|
|
max_runtime_secs: 30,
|
|
};
|
|
|
|
// Create terminal with a quick command
|
|
#[cfg(windows)]
|
|
let request = CreateTerminalRequest {
|
|
command: "cmd".to_string(),
|
|
args: vec!["/C".to_string(), "exit".to_string(), "0".to_string()],
|
|
cwd: None,
|
|
env: None,
|
|
output_byte_limit: None,
|
|
};
|
|
|
|
#[cfg(not(windows))]
|
|
let request = CreateTerminalRequest {
|
|
command: "true".to_string(),
|
|
args: vec![],
|
|
cwd: None,
|
|
env: None,
|
|
output_byte_limit: None,
|
|
};
|
|
|
|
let create_response = create_terminal(request, &config).await.unwrap();
|
|
let terminal_id = create_response.terminal_id;
|
|
|
|
// Wait for exit
|
|
let wait_response = wait_for_terminal_exit(
|
|
WaitForTerminalExitRequest {
|
|
terminal_id: terminal_id.clone(),
|
|
},
|
|
&config,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(wait_response.exit_status, 0);
|
|
|
|
// Release terminal
|
|
let _ = release_terminal(
|
|
ReleaseTerminalRequest {
|
|
terminal_id: terminal_id.clone(),
|
|
},
|
|
&config,
|
|
)
|
|
.await;
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_terminal_kill() {
|
|
let config = TerminalConfig {
|
|
enabled: true,
|
|
default_cwd: Some(std::env::current_dir().unwrap()),
|
|
env_allowlist: vec![],
|
|
command_blocklist: vec![],
|
|
output_byte_limit: 10_000,
|
|
max_runtime_secs: 30,
|
|
};
|
|
|
|
// Create terminal with a long-running command
|
|
#[cfg(windows)]
|
|
let request = CreateTerminalRequest {
|
|
command: "cmd".to_string(),
|
|
args: vec!["/C".to_string(), "timeout".to_string(), "/t".to_string(), "10".to_string()],
|
|
cwd: None,
|
|
env: None,
|
|
output_byte_limit: None,
|
|
};
|
|
|
|
#[cfg(not(windows))]
|
|
let request = CreateTerminalRequest {
|
|
command: "sleep".to_string(),
|
|
args: vec!["10".to_string()],
|
|
cwd: None,
|
|
env: None,
|
|
output_byte_limit: None,
|
|
};
|
|
|
|
let create_response = create_terminal(request, &config).await.unwrap();
|
|
let terminal_id = create_response.terminal_id;
|
|
|
|
// Wait a bit to ensure process is running
|
|
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
|
|
|
|
// Kill the terminal
|
|
let kill_response = kill_terminal(
|
|
KillTerminalCommandRequest {
|
|
terminal_id: terminal_id.clone(),
|
|
},
|
|
&config,
|
|
)
|
|
.await;
|
|
|
|
assert!(kill_response.is_ok());
|
|
|
|
// Release terminal
|
|
let _ = release_terminal(
|
|
ReleaseTerminalRequest {
|
|
terminal_id: terminal_id.clone(),
|
|
},
|
|
&config,
|
|
)
|
|
.await;
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_terminal_disabled() {
|
|
let config = TerminalConfig {
|
|
enabled: false,
|
|
default_cwd: Some(std::env::current_dir().unwrap()),
|
|
env_allowlist: vec![],
|
|
command_blocklist: vec![],
|
|
output_byte_limit: 10_000,
|
|
max_runtime_secs: 30,
|
|
};
|
|
|
|
let request = CreateTerminalRequest {
|
|
command: "echo".to_string(),
|
|
args: vec!["test".to_string()],
|
|
cwd: None,
|
|
env: None,
|
|
output_byte_limit: None,
|
|
};
|
|
|
|
let result = create_terminal(request, &config).await;
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_terminal_command_blocklist() {
|
|
let config = TerminalConfig {
|
|
enabled: true,
|
|
default_cwd: Some(std::env::current_dir().unwrap()),
|
|
env_allowlist: vec![],
|
|
command_blocklist: vec!["rm".to_string(), "del".to_string()],
|
|
output_byte_limit: 10_000,
|
|
max_runtime_secs: 30,
|
|
};
|
|
|
|
let request = CreateTerminalRequest {
|
|
command: "rm".to_string(),
|
|
args: vec!["-rf".to_string(), "/".to_string()],
|
|
cwd: None,
|
|
env: None,
|
|
output_byte_limit: None,
|
|
};
|
|
|
|
let result = create_terminal(request, &config).await;
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_terminal_output_truncation() {
|
|
let config = TerminalConfig {
|
|
enabled: true,
|
|
default_cwd: Some(std::env::current_dir().unwrap()),
|
|
env_allowlist: vec![],
|
|
command_blocklist: vec![],
|
|
output_byte_limit: 100, // Very small buffer
|
|
max_runtime_secs: 30,
|
|
};
|
|
|
|
// Create terminal that generates lots of output
|
|
#[cfg(windows)]
|
|
let request = CreateTerminalRequest {
|
|
command: "cmd".to_string(),
|
|
args: vec![
|
|
"/C".to_string(),
|
|
"for".to_string(),
|
|
"/L".to_string(),
|
|
"%i".to_string(),
|
|
"in".to_string(),
|
|
"(1,1,100)".to_string(),
|
|
"do".to_string(),
|
|
"@echo".to_string(),
|
|
"Line %i".to_string(),
|
|
],
|
|
cwd: None,
|
|
env: None,
|
|
output_byte_limit: Some(100),
|
|
};
|
|
|
|
#[cfg(not(windows))]
|
|
let request = CreateTerminalRequest {
|
|
command: "sh".to_string(),
|
|
args: vec![
|
|
"-c".to_string(),
|
|
"for i in $(seq 1 100); do echo Line $i; done".to_string(),
|
|
],
|
|
cwd: None,
|
|
env: None,
|
|
output_byte_limit: Some(100),
|
|
};
|
|
|
|
let create_response = create_terminal(request, &config).await.unwrap();
|
|
let terminal_id = create_response.terminal_id;
|
|
|
|
// Wait for command to complete
|
|
tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await;
|
|
|
|
// Get output
|
|
let output_response = get_terminal_output(
|
|
TerminalOutputRequest {
|
|
terminal_id: terminal_id.clone(),
|
|
},
|
|
&config,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Buffer should be truncated
|
|
assert!(output_response.truncated || output_response.output.len() <= 100);
|
|
|
|
// Release terminal
|
|
let _ = release_terminal(
|
|
ReleaseTerminalRequest {
|
|
terminal_id: terminal_id.clone(),
|
|
},
|
|
&config,
|
|
)
|
|
.await;
|
|
}
|