fix: connect to existing stack without starting new processes

- Add existing() constructors for BotServerInstance and BotUIInstance
- Use BOTSERVER_URL and BOTUI_URL env vars with sensible defaults
- Fix database defaults for existing stack mode (gbuser/gbuser)
This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2025-12-14 16:44:29 -03:00
parent 126abe2d10
commit e96b01cfc8
2 changed files with 85 additions and 27 deletions

View file

@ -122,16 +122,16 @@ impl TestContext {
pub fn database_url(&self) -> String { pub fn database_url(&self) -> String {
if self.use_existing_stack { if self.use_existing_stack {
// Credentials must be provided via environment or vault - no hardcoded fallbacks // For existing stack, use sensible defaults matching botserver's bootstrap
// For existing stack, expect VAULT_ADDR and credentials from vault // These can be overridden via environment variables if needed
let host = std::env::var("DB_HOST").unwrap_or_else(|_| "127.0.0.1".to_string()); let host = std::env::var("DB_HOST").unwrap_or_else(|_| "127.0.0.1".to_string());
let port = std::env::var("DB_PORT") let port = std::env::var("DB_PORT")
.ok() .ok()
.and_then(|p| p.parse().ok()) .and_then(|p| p.parse().ok())
.unwrap_or(DefaultPorts::POSTGRES); .unwrap_or(DefaultPorts::POSTGRES);
let user = std::env::var("DB_USER").expect("DB_USER must be set for existing stack"); // Default to gbuser/botserver which is what botserver bootstrap creates
let password = let user = std::env::var("DB_USER").unwrap_or_else(|_| "gbuser".to_string());
std::env::var("DB_PASSWORD").expect("DB_PASSWORD must be set for existing stack"); let password = std::env::var("DB_PASSWORD").unwrap_or_else(|_| "gbuser".to_string());
let database = std::env::var("DB_NAME").unwrap_or_else(|_| "botserver".to_string()); let database = std::env::var("DB_NAME").unwrap_or_else(|_| "botserver".to_string());
format!( format!(
"postgres://{}:{}@{}:{}/{}", "postgres://{}:{}@{}:{}/{}",
@ -451,12 +451,45 @@ pub struct BotServerInstance {
process: Option<std::process::Child>, process: Option<std::process::Child>,
} }
impl BotServerInstance {
/// Create an instance pointing to an already-running botserver
pub fn existing(url: &str) -> Self {
let port = url
.split(':')
.last()
.and_then(|p| p.parse().ok())
.unwrap_or(8080);
Self {
url: url.to_string(),
port,
stack_path: PathBuf::from("./botserver-stack"),
process: None,
}
}
}
pub struct BotUIInstance { pub struct BotUIInstance {
pub url: String, pub url: String,
pub port: u16, pub port: u16,
process: Option<std::process::Child>, process: Option<std::process::Child>,
} }
impl BotUIInstance {
/// Create an instance pointing to an already-running botui
pub fn existing(url: &str) -> Self {
let port = url
.split(':')
.last()
.and_then(|p| p.parse().ok())
.unwrap_or(3000);
Self {
url: url.to_string(),
port,
process: None,
}
}
}
impl BotUIInstance { impl BotUIInstance {
pub async fn start(ctx: &TestContext, botserver_url: &str) -> Result<Self> { pub async fn start(ctx: &TestContext, botserver_url: &str) -> Result<Self> {
let port = crate::ports::PortAllocator::allocate(); let port = crate::ports::PortAllocator::allocate();

View file

@ -22,18 +22,33 @@ impl E2ETestContext {
pub async fn setup() -> anyhow::Result<Self> { pub async fn setup() -> anyhow::Result<Self> {
// Default to USE_EXISTING_STACK for faster e2e tests // Default to USE_EXISTING_STACK for faster e2e tests
// Set FULL_BOOTSTRAP=1 to run full bootstrap instead // Set FULL_BOOTSTRAP=1 to run full bootstrap instead
let ctx = if std::env::var("FULL_BOOTSTRAP").is_ok() { let use_existing = std::env::var("FULL_BOOTSTRAP").is_err();
TestHarness::full().await?
} else {
// Use existing stack by default - much faster for e2e tests
// Make sure botserver is running: cargo run --package botserver
log::info!("Using existing stack (set FULL_BOOTSTRAP=1 for full bootstrap)");
TestHarness::with_existing_stack().await?
};
let server = ctx.start_botserver().await?;
// Start botui for serving the web interface let (ctx, server, ui) = if use_existing {
// Use existing stack - connect to running botserver/botui
// Make sure they are running:
// cargo run --package botserver
// BOTSERVER_URL=https://localhost:8080 cargo run --package botui
log::info!("Using existing stack (set FULL_BOOTSTRAP=1 for full bootstrap)");
let ctx = TestHarness::with_existing_stack().await?;
// Get URLs from env or use defaults
let botserver_url = std::env::var("BOTSERVER_URL")
.unwrap_or_else(|_| "https://localhost:8080".to_string());
let botui_url =
std::env::var("BOTUI_URL").unwrap_or_else(|_| "http://localhost:3000".to_string());
// Create a dummy server instance pointing to existing botserver
let server = BotServerInstance::existing(&botserver_url);
let ui = Some(BotUIInstance::existing(&botui_url));
(ctx, server, ui)
} else {
let ctx = TestHarness::full().await?;
let server = ctx.start_botserver().await?;
let ui = ctx.start_botui(&server.url).await.ok(); let ui = ctx.start_botui(&server.url).await.ok();
(ctx, server, ui)
};
Ok(Self { Ok(Self {
ctx, ctx,
@ -47,18 +62,28 @@ impl E2ETestContext {
pub async fn setup_with_browser() -> anyhow::Result<Self> { pub async fn setup_with_browser() -> anyhow::Result<Self> {
// Default to USE_EXISTING_STACK for faster e2e tests // Default to USE_EXISTING_STACK for faster e2e tests
// Set FULL_BOOTSTRAP=1 to run full bootstrap instead // Set FULL_BOOTSTRAP=1 to run full bootstrap instead
let ctx = if std::env::var("FULL_BOOTSTRAP").is_ok() { let use_existing = std::env::var("FULL_BOOTSTRAP").is_err();
TestHarness::full().await?
} else {
// Use existing stack by default - much faster for e2e tests
// Make sure botserver is running: cargo run --package botserver
log::info!("Using existing stack (set FULL_BOOTSTRAP=1 for full bootstrap)");
TestHarness::with_existing_stack().await?
};
let server = ctx.start_botserver().await?;
// Start botui for serving the web interface let (ctx, server, ui) = if use_existing {
// Use existing stack - connect to running botserver/botui
log::info!("Using existing stack (set FULL_BOOTSTRAP=1 for full bootstrap)");
let ctx = TestHarness::with_existing_stack().await?;
let botserver_url = std::env::var("BOTSERVER_URL")
.unwrap_or_else(|_| "https://localhost:8080".to_string());
let botui_url =
std::env::var("BOTUI_URL").unwrap_or_else(|_| "http://localhost:3000".to_string());
let server = BotServerInstance::existing(&botserver_url);
let ui = Some(BotUIInstance::existing(&botui_url));
(ctx, server, ui)
} else {
let ctx = TestHarness::full().await?;
let server = ctx.start_botserver().await?;
let ui = ctx.start_botui(&server.url).await.ok(); let ui = ctx.start_botui(&server.url).await.ok();
(ctx, server, ui)
};
let chromedriver = match ChromeDriverService::start(CHROMEDRIVER_PORT).await { let chromedriver = match ChromeDriverService::start(CHROMEDRIVER_PORT).await {
Ok(cd) => Some(cd), Ok(cd) => Some(cd),