feat: added e2e (#5)

* feat: added e2e

* fix: try fix

* fix: try fix

* fix: try fix

* fix: added more observability

* ci: fixed double trigger

* feat: partial e2e test with mock vm

* feat: more monkey tests

* feat: added coverage
This commit is contained in:
Finn Sheng
2026-02-08 18:50:35 -05:00
committed by GitHub
parent eafa229542
commit f6678e7069
10 changed files with 1090 additions and 12 deletions
+3
View File
@@ -21,6 +21,7 @@ use crate::{
};
const SSH_KEY_NAME: &str = "ssh_key";
#[cfg_attr(feature = "mock-vm", allow(dead_code))]
pub(crate) const VM_ROOT_LOG_NAME: &str = "vm_root.log";
pub(crate) const STATUS_FILE_NAME: &str = "status.txt";
pub(crate) const DEFAULT_SSH_USER: &str = "vibecoder";
@@ -217,6 +218,7 @@ fn generate_password() -> String {
Uuid::now_v7().simple().to_string()
}
#[cfg_attr(feature = "mock-vm", allow(dead_code))]
pub(crate) fn extract_ipv4(line: &str) -> Option<String> {
let mut current = String::new();
let mut best: Option<String> = None;
@@ -383,6 +385,7 @@ fn run_ssh_session(
Ok(())
}
#[cfg_attr(feature = "mock-vm", allow(dead_code))]
fn is_ipv4_candidate(candidate: &str) -> bool {
let parts: Vec<&str> = candidate.split('.').collect();
if parts.len() != 4 {
+66 -11
View File
@@ -103,17 +103,37 @@ pub fn run_manager(
let project_root = env::current_dir()?;
tracing::info!(root = %project_root.display(), "vm manager starting");
let _pid_guard = ensure_pid_file(&project_root)?;
run_manager_with(
&project_root,
args,
auto_shutdown_ms,
&RealVmExecutor,
ManagerOptions {
ensure_signed: true,
detach: true,
prepare_vm: true,
},
)
#[cfg(feature = "mock-vm")]
tracing::info!("vm manager using mock executor");
let executor: &dyn VmExecutor = {
#[cfg(feature = "mock-vm")]
{
&MockVmExecutor
}
#[cfg(not(feature = "mock-vm"))]
{
&RealVmExecutor
}
};
let options = {
#[cfg(feature = "mock-vm")]
{
ManagerOptions {
ensure_signed: false,
detach: true,
prepare_vm: false,
}
}
#[cfg(not(feature = "mock-vm"))]
{
ManagerOptions {
ensure_signed: true,
detach: true,
prepare_vm: true,
}
}
};
run_manager_with(&project_root, args, auto_shutdown_ms, executor, options)
}
fn spawn_manager_process(
@@ -468,6 +488,7 @@ fn read_client_pid(stream: &UnixStream) -> Option<u32> {
}
}
#[cfg_attr(feature = "mock-vm", allow(dead_code))]
fn spawn_manager_io(
config: Arc<Mutex<InstanceConfig>>,
instance_dir: PathBuf,
@@ -555,6 +576,7 @@ trait VmExecutor {
) -> Result<(), Box<dyn std::error::Error>>;
}
#[cfg_attr(feature = "mock-vm", allow(dead_code))]
struct RealVmExecutor;
impl VmExecutor for RealVmExecutor {
@@ -586,6 +608,39 @@ impl VmExecutor for RealVmExecutor {
}
}
#[cfg(feature = "mock-vm")]
struct MockVmExecutor;
#[cfg(feature = "mock-vm")]
impl VmExecutor for MockVmExecutor {
fn run_vm(
&self,
_args: vm::VmArg,
_extra_login_actions: Vec<LoginAction>,
_extra_shares: Vec<DirectoryShare>,
_config: Arc<Mutex<InstanceConfig>>,
_instance_dir: PathBuf,
vm_input_tx: Arc<Mutex<Option<mpsc::Sender<VmInput>>>>,
) -> Result<(), Box<dyn std::error::Error>> {
let (tx, rx) = mpsc::channel::<VmInput>();
*vm_input_tx.lock().unwrap() = Some(tx);
tracing::info!("mock vm executor running");
while let Ok(input) = rx.recv() {
match input {
VmInput::Shutdown => break,
VmInput::Bytes(bytes) => {
let text = String::from_utf8_lossy(&bytes);
if text.contains("systemctl poweroff") {
break;
}
}
}
}
tracing::info!("mock vm executor exiting");
Ok(())
}
}
fn run_manager_with(
project_root: &Path,
mut args: vm::VmArg,