pub mod docker;
pub mod tmux;
use anyhow::Result;
#[allow(dead_code)]
pub trait Backend: Send + Sync {
fn session_id(&self, name: &str) -> String {
name.to_owned()
}
fn check_version(&self) -> Result<String> {
Ok("unknown".into())
}
fn create_session(&self, backend_id: &str, working_dir: &str, command: &str) -> Result<()>;
fn kill_session(&self, backend_id: &str) -> Result<()>;
fn is_alive(&self, backend_id: &str) -> Result<bool>;
fn capture_output(&self, backend_id: &str, lines: usize) -> Result<String>;
fn send_input(&self, backend_id: &str, text: &str) -> Result<()>;
fn setup_logging(&self, backend_id: &str, log_path: &str) -> Result<()>;
fn resize(&self, _backend_id: &str, _cols: u16, _rows: u16) -> Result<()> {
Ok(())
}
fn spawn_attach(&self, _backend_id: &str) -> Result<tokio::process::Child> {
anyhow::bail!("spawn_attach not supported by this backend")
}
fn query_backend_id(&self, name: &str) -> Result<String> {
Ok(name.to_owned())
}
fn pane_command_line(&self, _backend_id: &str) -> Result<String> {
anyhow::bail!("pane_command_line not supported by this backend")
}
fn list_sessions(&self) -> Result<Vec<(String, String)>> {
Ok(Vec::new())
}
fn pane_info(&self, _backend_id: &str) -> Result<(String, String)> {
anyhow::bail!("pane_info not supported by this backend")
}
fn set_env(&self, _backend_id: &str, _key: &str, _value: &str) -> Result<()> {
Ok(())
}
}
#[cfg(test)]
pub(crate) struct StubBackend;
#[cfg(test)]
impl Backend for StubBackend {
fn create_session(&self, _: &str, _: &str, _: &str) -> Result<()> {
Ok(())
}
fn kill_session(&self, _: &str) -> Result<()> {
Ok(())
}
fn is_alive(&self, _: &str) -> Result<bool> {
Ok(true)
}
fn capture_output(&self, _: &str, _: usize) -> Result<String> {
Ok(String::new())
}
fn send_input(&self, _: &str, _: &str) -> Result<()> {
Ok(())
}
fn setup_logging(&self, _: &str, _: &str) -> Result<()> {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
struct MinimalBackend;
impl Backend for MinimalBackend {
fn create_session(&self, _: &str, _: &str, _: &str) -> Result<()> {
Ok(())
}
fn kill_session(&self, _: &str) -> Result<()> {
Ok(())
}
fn is_alive(&self, _: &str) -> Result<bool> {
Ok(true)
}
fn capture_output(&self, _: &str, _: usize) -> Result<String> {
Ok(String::new())
}
fn send_input(&self, _: &str, _: &str) -> Result<()> {
Ok(())
}
fn setup_logging(&self, _: &str, _: &str) -> Result<()> {
Ok(())
}
}
#[test]
fn test_default_session_id() {
let b = MinimalBackend;
assert_eq!(b.session_id("my-session"), "my-session");
}
#[test]
fn test_default_check_version() {
let b = MinimalBackend;
assert_eq!(b.check_version().unwrap(), "unknown");
}
#[test]
fn test_default_resize() {
let b = MinimalBackend;
assert!(b.resize("s", 120, 40).is_ok());
}
#[test]
fn test_default_spawn_attach() {
let b = MinimalBackend;
let err = b.spawn_attach("x").unwrap_err();
assert!(err.to_string().contains("spawn_attach not supported"));
}
#[test]
fn test_default_query_backend_id() {
let b = MinimalBackend;
assert_eq!(b.query_backend_id("my-session").unwrap(), "my-session");
}
#[test]
fn test_default_pane_command_line() {
let b = MinimalBackend;
let err = b.pane_command_line("x").unwrap_err();
assert!(err.to_string().contains("pane_command_line not supported"));
}
#[test]
fn test_default_list_sessions() {
let b = MinimalBackend;
assert!(b.list_sessions().unwrap().is_empty());
}
#[test]
fn test_default_pane_info() {
let b = MinimalBackend;
let err = b.pane_info("x").unwrap_err();
assert!(err.to_string().contains("pane_info not supported"));
}
#[test]
fn test_default_set_env() {
let b = MinimalBackend;
assert!(b.set_env("s", "KEY", "VALUE").is_ok());
}
#[test]
fn test_minimal_backend_required_methods() {
let b = MinimalBackend;
assert!(b.create_session("s", "/tmp", "echo hi").is_ok());
assert!(b.kill_session("s").is_ok());
assert!(b.is_alive("s").unwrap());
assert_eq!(b.capture_output("s", 10).unwrap(), "");
assert!(b.send_input("s", "hello").is_ok());
assert!(b.setup_logging("s", "/tmp/log").is_ok());
}
#[test]
fn test_stub_backend_methods() {
let b = StubBackend;
assert!(b.create_session("n", "d", "c").is_ok());
assert!(b.kill_session("n").is_ok());
assert!(b.is_alive("n").unwrap());
assert!(b.capture_output("n", 10).unwrap().is_empty());
assert!(b.send_input("n", "t").is_ok());
assert!(b.setup_logging("n", "p").is_ok());
}
#[test]
fn test_stub_backend_default_trait_methods() {
let b = StubBackend;
assert_eq!(b.session_id("my-session"), "my-session");
assert_eq!(b.check_version().unwrap(), "unknown");
assert!(b.resize("s", 120, 40).is_ok());
assert!(b.spawn_attach("s").is_err());
assert_eq!(b.query_backend_id("my-session").unwrap(), "my-session");
assert!(b.pane_command_line("s").is_err());
assert!(b.list_sessions().unwrap().is_empty());
assert!(b.pane_info("s").is_err());
assert!(b.set_env("s", "KEY", "VALUE").is_ok());
}
}