mirror of
https://github.com/zhom/banderole.git
synced 2026-05-11 20:22:42 +02:00
test: switch from windows-only debugging to a general solution
This commit is contained in:
+94
-38
@@ -495,7 +495,11 @@ impl BundlerTestHelper {
|
||||
/// Get the path to the banderole binary
|
||||
pub fn get_bundler_path() -> Result<PathBuf> {
|
||||
let target_dir = std::env::current_dir()?.join("target");
|
||||
let bundler_path = target_dir.join("debug/banderole");
|
||||
let bundler_path = if cfg!(windows) {
|
||||
target_dir.join("debug/banderole.exe")
|
||||
} else {
|
||||
target_dir.join("debug/banderole")
|
||||
};
|
||||
|
||||
if !bundler_path.exists() {
|
||||
// Build the bundler if it doesn't exist
|
||||
@@ -553,6 +557,18 @@ impl BundlerTestHelper {
|
||||
);
|
||||
}
|
||||
|
||||
// Debug: Print bundler output
|
||||
println!(
|
||||
"Bundler stdout: {}",
|
||||
String::from_utf8_lossy(&bundle_output.stdout)
|
||||
);
|
||||
if !bundle_output.stderr.is_empty() {
|
||||
println!(
|
||||
"Bundler stderr: {}",
|
||||
String::from_utf8_lossy(&bundle_output.stderr)
|
||||
);
|
||||
}
|
||||
|
||||
// Find the created executable
|
||||
let executable_name = custom_name.unwrap_or("test-project");
|
||||
let executable_path = output_dir.join(if cfg!(windows) {
|
||||
@@ -575,9 +591,31 @@ impl BundlerTestHelper {
|
||||
}
|
||||
|
||||
if !executable_path.exists() {
|
||||
// List directory contents for debugging
|
||||
let dir_contents = fs::read_dir(output_dir)
|
||||
.map(|entries| {
|
||||
entries
|
||||
.filter_map(|e| e.ok())
|
||||
.map(|entry| {
|
||||
let path = entry.path();
|
||||
let metadata = fs::metadata(&path).ok();
|
||||
format!(
|
||||
"{} (size: {}, is_file: {})",
|
||||
entry.file_name().to_string_lossy(),
|
||||
metadata.as_ref().map(|m| m.len()).unwrap_or(0),
|
||||
metadata.as_ref().map(|m| m.is_file()).unwrap_or(false)
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.unwrap_or_else(|e| vec![format!("Error reading directory: {}", e)]);
|
||||
|
||||
anyhow::bail!(
|
||||
"Executable was not created at {}",
|
||||
executable_path.display()
|
||||
"Executable was not created at {}\nExpected name: {}\nOutput directory: {}\nOutput directory contents: {:?}",
|
||||
executable_path.display(),
|
||||
executable_name,
|
||||
output_dir.display(),
|
||||
dir_contents
|
||||
);
|
||||
}
|
||||
|
||||
@@ -590,39 +628,40 @@ impl BundlerTestHelper {
|
||||
args: &[&str],
|
||||
env_vars: &[(&str, &str)],
|
||||
) -> Result<std::process::Output> {
|
||||
// Windows-specific debugging for "program not found" errors
|
||||
#[cfg(windows)]
|
||||
{
|
||||
if !executable_path.exists() {
|
||||
anyhow::bail!(
|
||||
"Windows: Executable does not exist at path: {}\nParent directory exists: {}\nParent directory contents: {:?}",
|
||||
executable_path.display(),
|
||||
executable_path.parent().map(|p| p.exists()).unwrap_or(false),
|
||||
executable_path.parent()
|
||||
.and_then(|p| fs::read_dir(p).ok())
|
||||
.map(|entries| entries.filter_map(|e| e.ok()).map(|e| e.file_name().to_string_lossy().to_string()).collect::<Vec<_>>())
|
||||
.unwrap_or_else(|| vec!["Could not read directory".to_string()])
|
||||
);
|
||||
}
|
||||
// Verify executable exists and is accessible
|
||||
if !executable_path.exists() {
|
||||
let parent_contents = executable_path
|
||||
.parent()
|
||||
.and_then(|p| fs::read_dir(p).ok())
|
||||
.map(|entries| {
|
||||
entries
|
||||
.filter_map(|e| e.ok())
|
||||
.map(|e| e.file_name().to_string_lossy().to_string())
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.unwrap_or_else(|| vec!["Could not read directory".to_string()]);
|
||||
|
||||
if let Ok(metadata) = fs::metadata(executable_path) {
|
||||
if !metadata.is_file() {
|
||||
anyhow::bail!(
|
||||
"Windows: Path exists but is not a file: {} (is_dir: {})",
|
||||
executable_path.display(),
|
||||
metadata.is_dir()
|
||||
);
|
||||
}
|
||||
println!(
|
||||
"Windows debug: Executable found, size: {} bytes",
|
||||
metadata.len()
|
||||
);
|
||||
} else {
|
||||
anyhow::bail!(
|
||||
"Executable does not exist at path: {}\nParent directory exists: {}\nParent directory contents: {:?}",
|
||||
executable_path.display(),
|
||||
executable_path.parent().map(|p| p.exists()).unwrap_or(false),
|
||||
parent_contents
|
||||
);
|
||||
}
|
||||
|
||||
if let Ok(metadata) = fs::metadata(executable_path) {
|
||||
if !metadata.is_file() {
|
||||
anyhow::bail!(
|
||||
"Windows: Cannot read metadata for executable: {}",
|
||||
executable_path.display()
|
||||
"Path exists but is not a file: {} (is_dir: {})",
|
||||
executable_path.display(),
|
||||
metadata.is_dir()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
anyhow::bail!(
|
||||
"Cannot read metadata for executable: {}",
|
||||
executable_path.display()
|
||||
);
|
||||
}
|
||||
|
||||
// Make executable on Unix
|
||||
@@ -635,13 +674,33 @@ impl BundlerTestHelper {
|
||||
fs::set_permissions(executable_path, perms)?;
|
||||
}
|
||||
|
||||
let mut cmd = Command::new(executable_path);
|
||||
// On Windows, ensure we're using the full path and handle potential issues
|
||||
let mut cmd = if cfg!(windows) {
|
||||
// Use the full canonical path on Windows to avoid "program not found" issues
|
||||
let canonical_path = executable_path.canonicalize().with_context(|| {
|
||||
format!("Failed to canonicalize path: {}", executable_path.display())
|
||||
})?;
|
||||
println!(
|
||||
"Windows: Using canonical path: {}",
|
||||
canonical_path.display()
|
||||
);
|
||||
Command::new(canonical_path)
|
||||
} else {
|
||||
Command::new(executable_path)
|
||||
};
|
||||
|
||||
cmd.args(args);
|
||||
|
||||
for (key, value) in env_vars {
|
||||
cmd.env(key, value);
|
||||
}
|
||||
|
||||
println!(
|
||||
"Executing: {} with args: {:?}",
|
||||
executable_path.display(),
|
||||
args
|
||||
);
|
||||
|
||||
let output = cmd.output().with_context(|| {
|
||||
format!(
|
||||
"Failed to execute command: {}\nArgs: {:?}\nEnv vars: {:?}\nWorking directory: {:?}",
|
||||
@@ -674,14 +733,11 @@ impl BundlerTestHelper {
|
||||
Ok(result) => result.map_err(|e| anyhow::anyhow!("Command execution failed: {}", e)),
|
||||
Err(_) => {
|
||||
// Timeout occurred, kill the process
|
||||
#[cfg(unix)]
|
||||
{
|
||||
if cfg!(unix) {
|
||||
let _ = std::process::Command::new("kill")
|
||||
.args(["-9", &child_id.to_string()])
|
||||
.output();
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
} else if cfg!(windows) {
|
||||
let _ = std::process::Command::new("taskkill")
|
||||
.args(["/F", "/PID", &child_id.to_string()])
|
||||
.output();
|
||||
|
||||
@@ -28,41 +28,40 @@ async fn test_concurrent_first_launch() -> Result<()> {
|
||||
false, // No compression for faster testing
|
||||
)?;
|
||||
|
||||
// Windows-specific debugging for executable creation
|
||||
#[cfg(windows)]
|
||||
{
|
||||
eprintln!(
|
||||
"Windows debug: Executable path created: {}",
|
||||
executable_path.display()
|
||||
);
|
||||
eprintln!(
|
||||
"Windows debug: Executable exists: {}",
|
||||
executable_path.exists()
|
||||
);
|
||||
if executable_path.exists() {
|
||||
if let Ok(metadata) = std::fs::metadata(&executable_path) {
|
||||
eprintln!("Windows debug: Executable size: {} bytes", metadata.len());
|
||||
eprintln!("Windows debug: Executable is file: {}", metadata.is_file());
|
||||
} else {
|
||||
eprintln!("Windows debug: Cannot read executable metadata");
|
||||
}
|
||||
// Debug executable creation
|
||||
eprintln!(
|
||||
"Debug: Executable path created: {}",
|
||||
executable_path.display()
|
||||
);
|
||||
eprintln!("Debug: Executable exists: {}", executable_path.exists());
|
||||
if executable_path.exists() {
|
||||
if let Ok(metadata) = std::fs::metadata(&executable_path) {
|
||||
eprintln!("Debug: Executable size: {} bytes", metadata.len());
|
||||
eprintln!("Debug: Executable is file: {}", metadata.is_file());
|
||||
} else {
|
||||
eprintln!("Windows debug: Executable does not exist!");
|
||||
if let Some(parent) = executable_path.parent() {
|
||||
eprintln!("Windows debug: Parent directory: {}", parent.display());
|
||||
eprintln!("Windows debug: Parent exists: {}", parent.exists());
|
||||
if let Ok(entries) = std::fs::read_dir(parent) {
|
||||
eprintln!("Windows debug: Parent directory contents:");
|
||||
for entry in entries.flatten() {
|
||||
eprintln!(" - {}", entry.file_name().to_string_lossy());
|
||||
}
|
||||
} else {
|
||||
eprintln!("Windows debug: Cannot read parent directory");
|
||||
eprintln!("Debug: Cannot read executable metadata");
|
||||
}
|
||||
} else {
|
||||
eprintln!("Debug: Executable does not exist!");
|
||||
if let Some(parent) = executable_path.parent() {
|
||||
eprintln!("Debug: Parent directory: {}", parent.display());
|
||||
eprintln!("Debug: Parent exists: {}", parent.exists());
|
||||
if let Ok(entries) = std::fs::read_dir(parent) {
|
||||
eprintln!("Debug: Parent directory contents:");
|
||||
for entry in entries.flatten() {
|
||||
eprintln!(" - {}", entry.file_name().to_string_lossy());
|
||||
}
|
||||
} else {
|
||||
eprintln!("Debug: Cannot read parent directory");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Give the filesystem a moment to settle on Windows
|
||||
if cfg!(windows) {
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
}
|
||||
|
||||
// Clear any existing cache to ensure we test first launch
|
||||
TestCacheManager::clear_application_cache()?;
|
||||
|
||||
@@ -85,33 +84,54 @@ async fn test_concurrent_first_launch() -> Result<()> {
|
||||
// Wait for all threads to be ready
|
||||
barrier.wait();
|
||||
|
||||
// Add a small staggered delay to reduce race conditions on Windows
|
||||
std::thread::sleep(std::time::Duration::from_millis(i as u64 * 10));
|
||||
|
||||
let thread_start = Instant::now();
|
||||
|
||||
// Execute the binary using the test helper
|
||||
let output = BundlerTestHelper::run_executable(
|
||||
executable_path.as_ref(),
|
||||
&[&format!("--thread-id={i}")],
|
||||
&[("TEST_VAR", &format!("thread_{i}"))],
|
||||
)
|
||||
.map_err(|e| {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
eprintln!(
|
||||
"Windows debug - Thread {}: Failed to execute binary at {}",
|
||||
i,
|
||||
executable_path.as_ref().display()
|
||||
);
|
||||
eprintln!("Windows debug - Thread {i}: Error details: {e:?}");
|
||||
eprintln!("Windows debug - Thread {i}: Error chain:");
|
||||
let mut source = e.source();
|
||||
let mut level = 0;
|
||||
while let Some(err) = source {
|
||||
eprintln!("Windows debug - Thread {i}: Level {level}: {err}");
|
||||
source = err.source();
|
||||
level += 1;
|
||||
// Execute the binary using the test helper with retry logic for Windows
|
||||
let mut last_error = None;
|
||||
let mut output = None;
|
||||
|
||||
for attempt in 1..=3 {
|
||||
match BundlerTestHelper::run_executable(
|
||||
executable_path.as_ref(),
|
||||
&[&format!("--thread-id={i}")],
|
||||
&[("TEST_VAR", &format!("thread_{i}"))],
|
||||
) {
|
||||
Ok(result) => {
|
||||
output = Some(result);
|
||||
break;
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Thread {i}: Attempt {attempt} failed: {e}");
|
||||
last_error = Some(e);
|
||||
if attempt < 3 {
|
||||
std::thread::sleep(std::time::Duration::from_millis(
|
||||
100 * attempt as u64,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
anyhow::anyhow!("Failed to execute binary: {e}")
|
||||
}
|
||||
|
||||
let output = output.ok_or_else(|| {
|
||||
let e = last_error.unwrap();
|
||||
eprintln!(
|
||||
"Thread {}: Failed to execute binary at {} after 3 attempts",
|
||||
i,
|
||||
executable_path.as_ref().display()
|
||||
);
|
||||
eprintln!("Thread {i}: Final error details: {e:?}");
|
||||
eprintln!("Thread {i}: Error chain:");
|
||||
let mut source = e.source();
|
||||
let mut level = 0;
|
||||
while let Some(err) = source {
|
||||
eprintln!("Thread {i}: Level {level}: {err}");
|
||||
source = err.source();
|
||||
level += 1;
|
||||
}
|
||||
anyhow::anyhow!("Failed to execute binary after retries: {e}")
|
||||
})?;
|
||||
|
||||
let duration = thread_start.elapsed();
|
||||
@@ -218,50 +238,43 @@ async fn test_cached_concurrent_execution() -> Result<()> {
|
||||
false,
|
||||
)?;
|
||||
|
||||
// Windows-specific debugging for executable creation
|
||||
#[cfg(windows)]
|
||||
{
|
||||
eprintln!(
|
||||
"Windows debug (cached): Executable path created: {}",
|
||||
executable_path.display()
|
||||
);
|
||||
eprintln!(
|
||||
"Windows debug (cached): Executable exists: {}",
|
||||
executable_path.exists()
|
||||
);
|
||||
if executable_path.exists() {
|
||||
if let Ok(metadata) = std::fs::metadata(&executable_path) {
|
||||
eprintln!(
|
||||
"Windows debug (cached): Executable size: {} bytes",
|
||||
metadata.len()
|
||||
);
|
||||
eprintln!(
|
||||
"Windows debug (cached): Executable is file: {}",
|
||||
metadata.is_file()
|
||||
);
|
||||
} else {
|
||||
eprintln!("Windows debug (cached): Cannot read executable metadata");
|
||||
}
|
||||
// Debug executable creation
|
||||
eprintln!(
|
||||
"Debug (cached): Executable path created: {}",
|
||||
executable_path.display()
|
||||
);
|
||||
eprintln!(
|
||||
"Debug (cached): Executable exists: {}",
|
||||
executable_path.exists()
|
||||
);
|
||||
if executable_path.exists() {
|
||||
if let Ok(metadata) = std::fs::metadata(&executable_path) {
|
||||
eprintln!("Debug (cached): Executable size: {} bytes", metadata.len());
|
||||
eprintln!("Debug (cached): Executable is file: {}", metadata.is_file());
|
||||
} else {
|
||||
eprintln!("Windows debug (cached): Executable does not exist!");
|
||||
if let Some(parent) = executable_path.parent() {
|
||||
eprintln!(
|
||||
"Windows debug (cached): Parent directory: {}",
|
||||
parent.display()
|
||||
);
|
||||
eprintln!("Windows debug (cached): Parent exists: {}", parent.exists());
|
||||
if let Ok(entries) = std::fs::read_dir(parent) {
|
||||
eprintln!("Windows debug (cached): Parent directory contents:");
|
||||
for entry in entries.flatten() {
|
||||
eprintln!(" - {}", entry.file_name().to_string_lossy());
|
||||
}
|
||||
} else {
|
||||
eprintln!("Windows debug (cached): Cannot read parent directory");
|
||||
eprintln!("Debug (cached): Cannot read executable metadata");
|
||||
}
|
||||
} else {
|
||||
eprintln!("Debug (cached): Executable does not exist!");
|
||||
if let Some(parent) = executable_path.parent() {
|
||||
eprintln!("Debug (cached): Parent directory: {}", parent.display());
|
||||
eprintln!("Debug (cached): Parent exists: {}", parent.exists());
|
||||
if let Ok(entries) = std::fs::read_dir(parent) {
|
||||
eprintln!("Debug (cached): Parent directory contents:");
|
||||
for entry in entries.flatten() {
|
||||
eprintln!(" - {}", entry.file_name().to_string_lossy());
|
||||
}
|
||||
} else {
|
||||
eprintln!("Debug (cached): Cannot read parent directory");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Give the filesystem a moment to settle on Windows
|
||||
if cfg!(windows) {
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
}
|
||||
|
||||
// Clear cache and run once to populate it
|
||||
TestCacheManager::clear_application_cache()?;
|
||||
|
||||
@@ -290,32 +303,54 @@ async fn test_cached_concurrent_execution() -> Result<()> {
|
||||
let handle = thread::spawn(move || -> Result<(usize, Duration)> {
|
||||
barrier.wait();
|
||||
|
||||
// Add a small staggered delay to reduce race conditions on Windows
|
||||
std::thread::sleep(std::time::Duration::from_millis(i as u64 * 10));
|
||||
|
||||
let thread_start = Instant::now();
|
||||
|
||||
let output = BundlerTestHelper::run_executable(
|
||||
executable_path.as_ref(),
|
||||
&[],
|
||||
&[("TEST_VAR", &format!("cached_{i}"))],
|
||||
)
|
||||
.map_err(|e| {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
eprintln!(
|
||||
"Windows debug - Cached thread {}: Failed to execute binary at {}",
|
||||
i,
|
||||
executable_path.as_ref().display()
|
||||
);
|
||||
eprintln!("Windows debug - Cached thread {e}: Error details: {e:?}");
|
||||
eprintln!("Windows debug - Cached thread {i}: Error chain:");
|
||||
let mut source = e.source();
|
||||
let mut level = 0;
|
||||
while let Some(err) = source {
|
||||
eprintln!("Windows debug - Cached thread {i}: Level {level}: {err}");
|
||||
source = err.source();
|
||||
level += 1;
|
||||
// Execute the binary using the test helper with retry logic for Windows
|
||||
let mut last_error = None;
|
||||
let mut output = None;
|
||||
|
||||
for attempt in 1..=3 {
|
||||
match BundlerTestHelper::run_executable(
|
||||
executable_path.as_ref(),
|
||||
&[],
|
||||
&[("TEST_VAR", &format!("cached_{i}"))],
|
||||
) {
|
||||
Ok(result) => {
|
||||
output = Some(result);
|
||||
break;
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Cached thread {i}: Attempt {attempt} failed: {e}");
|
||||
last_error = Some(e);
|
||||
if attempt < 3 {
|
||||
std::thread::sleep(std::time::Duration::from_millis(
|
||||
100 * attempt as u64,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
anyhow::anyhow!("Failed to execute binary: {}", e)
|
||||
}
|
||||
|
||||
let output = output.ok_or_else(|| {
|
||||
let e = last_error.unwrap();
|
||||
eprintln!(
|
||||
"Cached thread {}: Failed to execute binary at {} after 3 attempts",
|
||||
i,
|
||||
executable_path.as_ref().display()
|
||||
);
|
||||
eprintln!("Cached thread {i}: Final error details: {e:?}");
|
||||
eprintln!("Cached thread {i}: Error chain:");
|
||||
let mut source = e.source();
|
||||
let mut level = 0;
|
||||
while let Some(err) = source {
|
||||
eprintln!("Cached thread {i}: Level {level}: {err}");
|
||||
source = err.source();
|
||||
level += 1;
|
||||
}
|
||||
anyhow::anyhow!("Failed to execute binary after retries: {}", e)
|
||||
})?;
|
||||
|
||||
let duration = thread_start.elapsed();
|
||||
|
||||
Reference in New Issue
Block a user