feat: fix flaky generate test and format tunnel.rs
- Fix race condition in generate test temp_dir() by using PID + atomic counter instead of nanosecond timestamps that collide under parallel test execution - Apply cargo fmt to tunnel.rs for consistent formatting Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
parent
10b8b24dce
commit
32a29c89f2
+6
-5
@@ -200,12 +200,13 @@ mod tests {
|
|||||||
use crate::redact;
|
use crate::redact;
|
||||||
|
|
||||||
fn temp_dir() -> std::path::PathBuf {
|
fn temp_dir() -> std::path::PathBuf {
|
||||||
|
// Use process ID + monotonic counter to avoid collisions when tests run in parallel
|
||||||
|
static COUNTER: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
|
||||||
|
let unique = COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||||
std::env::temp_dir().join(format!(
|
std::env::temp_dir().join(format!(
|
||||||
"rustunnel_generate_test_{}",
|
"rustunnel_generate_test_{}_{}",
|
||||||
std::time::SystemTime::now()
|
std::process::id(),
|
||||||
.duration_since(std::time::UNIX_EPOCH)
|
unique
|
||||||
.unwrap_or_default()
|
|
||||||
.as_nanos()
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+37
-65
@@ -2552,8 +2552,7 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Start listener
|
// Start listener
|
||||||
let bind_addr: SocketAddr =
|
let bind_addr: SocketAddr = format!("127.0.0.1:{}", listener_port).parse().unwrap();
|
||||||
format!("127.0.0.1:{}", listener_port).parse().unwrap();
|
|
||||||
let listener_config = ListenerConfig {
|
let listener_config = ListenerConfig {
|
||||||
bind_addr,
|
bind_addr,
|
||||||
server_cert_path: path_arc!(dir.path().join("server.crt")),
|
server_cert_path: path_arc!(dir.path().join("server.crt")),
|
||||||
@@ -2561,13 +2560,11 @@ mod tests {
|
|||||||
ca_cert_path: path_arc!(dir.path().join("ca.pem")),
|
ca_cert_path: path_arc!(dir.path().join("ca.pem")),
|
||||||
auth_token: Arc::new(token.clone()),
|
auth_token: Arc::new(token.clone()),
|
||||||
};
|
};
|
||||||
let listener_task =
|
let listener_task = tokio::spawn(async move { run_listener(listener_config).await });
|
||||||
tokio::spawn(async move { run_listener(listener_config).await });
|
|
||||||
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
|
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
|
||||||
|
|
||||||
// Start connector with SOCKS5 (has reconnect loop built-in)
|
// Start connector with SOCKS5 (has reconnect loop built-in)
|
||||||
let socks_addr: SocketAddr =
|
let socks_addr: SocketAddr = format!("127.0.0.1:{}", socks_port).parse().unwrap();
|
||||||
format!("127.0.0.1:{}", socks_port).parse().unwrap();
|
|
||||||
let connector_config = ConnectorConfig {
|
let connector_config = ConnectorConfig {
|
||||||
target_host: "127.0.0.1".to_string(),
|
target_host: "127.0.0.1".to_string(),
|
||||||
target_port: listener_port,
|
target_port: listener_port,
|
||||||
@@ -2576,9 +2573,10 @@ mod tests {
|
|||||||
ca_cert_path: path_arc!(dir.path().join("ca.pem")),
|
ca_cert_path: path_arc!(dir.path().join("ca.pem")),
|
||||||
auth_token: Arc::new(token.clone()),
|
auth_token: Arc::new(token.clone()),
|
||||||
};
|
};
|
||||||
let connector_task = tokio::spawn(async move {
|
let connector_task =
|
||||||
run_connector_with_socks(connector_config, socks_addr).await
|
tokio::spawn(
|
||||||
});
|
async move { run_connector_with_socks(connector_config, socks_addr).await },
|
||||||
|
);
|
||||||
tokio::time::sleep(std::time::Duration::from_millis(400)).await;
|
tokio::time::sleep(std::time::Duration::from_millis(400)).await;
|
||||||
|
|
||||||
// Step 1: Verify initial connection works
|
// Step 1: Verify initial connection works
|
||||||
@@ -2599,8 +2597,7 @@ mod tests {
|
|||||||
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
|
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
|
||||||
|
|
||||||
// Step 3: Restart listener
|
// Step 3: Restart listener
|
||||||
let bind_addr2: SocketAddr =
|
let bind_addr2: SocketAddr = format!("127.0.0.1:{}", listener_port).parse().unwrap();
|
||||||
format!("127.0.0.1:{}", listener_port).parse().unwrap();
|
|
||||||
let listener_config2 = ListenerConfig {
|
let listener_config2 = ListenerConfig {
|
||||||
bind_addr: bind_addr2,
|
bind_addr: bind_addr2,
|
||||||
server_cert_path: path_arc!(dir.path().join("server.crt")),
|
server_cert_path: path_arc!(dir.path().join("server.crt")),
|
||||||
@@ -2608,8 +2605,7 @@ mod tests {
|
|||||||
ca_cert_path: path_arc!(dir.path().join("ca.pem")),
|
ca_cert_path: path_arc!(dir.path().join("ca.pem")),
|
||||||
auth_token: Arc::new(token.clone()),
|
auth_token: Arc::new(token.clone()),
|
||||||
};
|
};
|
||||||
let listener_task2 =
|
let listener_task2 = tokio::spawn(async move { run_listener(listener_config2).await });
|
||||||
tokio::spawn(async move { run_listener(listener_config2).await });
|
|
||||||
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
|
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
|
||||||
|
|
||||||
// Step 4: Wait for reconnect loop to re-establish the tunnel
|
// Step 4: Wait for reconnect loop to re-establish the tunnel
|
||||||
@@ -2664,11 +2660,7 @@ mod tests {
|
|||||||
|
|
||||||
// Abort should cause graceful shutdown within reasonable time
|
// Abort should cause graceful shutdown within reasonable time
|
||||||
handle.abort();
|
handle.abort();
|
||||||
let result = tokio::time::timeout(
|
let result = tokio::time::timeout(std::time::Duration::from_secs(3), handle).await;
|
||||||
std::time::Duration::from_secs(3),
|
|
||||||
handle,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
result.is_ok(),
|
result.is_ok(),
|
||||||
@@ -2692,8 +2684,7 @@ mod tests {
|
|||||||
let socks_port = get_free_port();
|
let socks_port = get_free_port();
|
||||||
|
|
||||||
// Start listener
|
// Start listener
|
||||||
let bind_addr: SocketAddr =
|
let bind_addr: SocketAddr = format!("127.0.0.1:{}", listener_port).parse().unwrap();
|
||||||
format!("127.0.0.1:{}", listener_port).parse().unwrap();
|
|
||||||
let listener_config = ListenerConfig {
|
let listener_config = ListenerConfig {
|
||||||
bind_addr,
|
bind_addr,
|
||||||
server_cert_path: path_arc!(dir.path().join("server.crt")),
|
server_cert_path: path_arc!(dir.path().join("server.crt")),
|
||||||
@@ -2701,12 +2692,10 @@ mod tests {
|
|||||||
ca_cert_path: path_arc!(dir.path().join("ca.pem")),
|
ca_cert_path: path_arc!(dir.path().join("ca.pem")),
|
||||||
auth_token: Arc::new(token.clone()),
|
auth_token: Arc::new(token.clone()),
|
||||||
};
|
};
|
||||||
let listener_task =
|
let listener_task = tokio::spawn(async move { run_listener(listener_config).await });
|
||||||
tokio::spawn(async move { run_listener(listener_config).await });
|
|
||||||
|
|
||||||
// Start connector
|
// Start connector
|
||||||
let socks_addr: SocketAddr =
|
let socks_addr: SocketAddr = format!("127.0.0.1:{}", socks_port).parse().unwrap();
|
||||||
format!("127.0.0.1:{}", socks_port).parse().unwrap();
|
|
||||||
let connector_config = ConnectorConfig {
|
let connector_config = ConnectorConfig {
|
||||||
target_host: "127.0.0.1".to_string(),
|
target_host: "127.0.0.1".to_string(),
|
||||||
target_port: listener_port,
|
target_port: listener_port,
|
||||||
@@ -2715,18 +2704,15 @@ mod tests {
|
|||||||
ca_cert_path: path_arc!(dir.path().join("ca.pem")),
|
ca_cert_path: path_arc!(dir.path().join("ca.pem")),
|
||||||
auth_token: Arc::new(token.clone()),
|
auth_token: Arc::new(token.clone()),
|
||||||
};
|
};
|
||||||
let connector_task = tokio::spawn(async move {
|
let connector_task =
|
||||||
run_connector_with_socks(connector_config, socks_addr).await
|
tokio::spawn(
|
||||||
});
|
async move { run_connector_with_socks(connector_config, socks_addr).await },
|
||||||
|
);
|
||||||
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
|
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
|
||||||
|
|
||||||
// Abort connector — should shut down gracefully
|
// Abort connector — should shut down gracefully
|
||||||
connector_task.abort();
|
connector_task.abort();
|
||||||
let result = tokio::time::timeout(
|
let result = tokio::time::timeout(std::time::Duration::from_secs(3), connector_task).await;
|
||||||
std::time::Duration::from_secs(3),
|
|
||||||
connector_task,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
result.is_ok(),
|
result.is_ok(),
|
||||||
@@ -2773,8 +2759,7 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Start listener
|
// Start listener
|
||||||
let bind_addr: SocketAddr =
|
let bind_addr: SocketAddr = format!("127.0.0.1:{}", listener_port).parse().unwrap();
|
||||||
format!("127.0.0.1:{}", listener_port).parse().unwrap();
|
|
||||||
let listener_config = ListenerConfig {
|
let listener_config = ListenerConfig {
|
||||||
bind_addr,
|
bind_addr,
|
||||||
server_cert_path: path_arc!(dir.path().join("server.crt")),
|
server_cert_path: path_arc!(dir.path().join("server.crt")),
|
||||||
@@ -2782,13 +2767,11 @@ mod tests {
|
|||||||
ca_cert_path: path_arc!(dir.path().join("ca.pem")),
|
ca_cert_path: path_arc!(dir.path().join("ca.pem")),
|
||||||
auth_token: Arc::new(token.clone()),
|
auth_token: Arc::new(token.clone()),
|
||||||
};
|
};
|
||||||
let listener_task =
|
let listener_task = tokio::spawn(async move { run_listener(listener_config).await });
|
||||||
tokio::spawn(async move { run_listener(listener_config).await });
|
|
||||||
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
|
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
|
||||||
|
|
||||||
// Start connector
|
// Start connector
|
||||||
let socks_addr: SocketAddr =
|
let socks_addr: SocketAddr = format!("127.0.0.1:{}", socks_port).parse().unwrap();
|
||||||
format!("127.0.0.1:{}", socks_port).parse().unwrap();
|
|
||||||
let connector_config = ConnectorConfig {
|
let connector_config = ConnectorConfig {
|
||||||
target_host: "127.0.0.1".to_string(),
|
target_host: "127.0.0.1".to_string(),
|
||||||
target_port: listener_port,
|
target_port: listener_port,
|
||||||
@@ -2797,9 +2780,10 @@ mod tests {
|
|||||||
ca_cert_path: path_arc!(dir.path().join("ca.pem")),
|
ca_cert_path: path_arc!(dir.path().join("ca.pem")),
|
||||||
auth_token: Arc::new(token.clone()),
|
auth_token: Arc::new(token.clone()),
|
||||||
};
|
};
|
||||||
let connector_task = tokio::spawn(async move {
|
let connector_task =
|
||||||
run_connector_with_socks(connector_config, socks_addr).await
|
tokio::spawn(
|
||||||
});
|
async move { run_connector_with_socks(connector_config, socks_addr).await },
|
||||||
|
);
|
||||||
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
|
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
|
||||||
|
|
||||||
// Open two concurrent streams and send unique data
|
// Open two concurrent streams and send unique data
|
||||||
@@ -2828,11 +2812,8 @@ mod tests {
|
|||||||
|
|
||||||
// Now shutdown the connector
|
// Now shutdown the connector
|
||||||
connector_task.abort();
|
connector_task.abort();
|
||||||
let shutdown_result = tokio::time::timeout(
|
let shutdown_result =
|
||||||
std::time::Duration::from_secs(3),
|
tokio::time::timeout(std::time::Duration::from_secs(3), connector_task).await;
|
||||||
connector_task,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
assert!(
|
assert!(
|
||||||
shutdown_result.is_ok(),
|
shutdown_result.is_ok(),
|
||||||
"Connector should shut down gracefully even after active streams"
|
"Connector should shut down gracefully even after active streams"
|
||||||
@@ -2840,10 +2821,7 @@ mod tests {
|
|||||||
|
|
||||||
// Verify ports are released
|
// Verify ports are released
|
||||||
let socks_rebind = TcpListener::bind(socks_addr).await;
|
let socks_rebind = TcpListener::bind(socks_addr).await;
|
||||||
assert!(
|
assert!(socks_rebind.is_ok(), "SOCKS5 port should be released");
|
||||||
socks_rebind.is_ok(),
|
|
||||||
"SOCKS5 port should be released"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
listener_task.abort();
|
listener_task.abort();
|
||||||
@@ -2860,8 +2838,7 @@ mod tests {
|
|||||||
let listener_port = get_free_port();
|
let listener_port = get_free_port();
|
||||||
let socks_port = get_free_port();
|
let socks_port = get_free_port();
|
||||||
|
|
||||||
let bind_addr: SocketAddr =
|
let bind_addr: SocketAddr = format!("127.0.0.1:{}", listener_port).parse().unwrap();
|
||||||
format!("127.0.0.1:{}", listener_port).parse().unwrap();
|
|
||||||
let listener_config = ListenerConfig {
|
let listener_config = ListenerConfig {
|
||||||
bind_addr,
|
bind_addr,
|
||||||
server_cert_path: path_arc!(dir.path().join("server.crt")),
|
server_cert_path: path_arc!(dir.path().join("server.crt")),
|
||||||
@@ -2869,12 +2846,10 @@ mod tests {
|
|||||||
ca_cert_path: path_arc!(dir.path().join("ca.pem")),
|
ca_cert_path: path_arc!(dir.path().join("ca.pem")),
|
||||||
auth_token: Arc::new(token.clone()),
|
auth_token: Arc::new(token.clone()),
|
||||||
};
|
};
|
||||||
let listener_task =
|
let listener_task = tokio::spawn(async move { run_listener(listener_config).await });
|
||||||
tokio::spawn(async move { run_listener(listener_config).await });
|
|
||||||
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
|
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
|
||||||
|
|
||||||
let socks_addr: SocketAddr =
|
let socks_addr: SocketAddr = format!("127.0.0.1:{}", socks_port).parse().unwrap();
|
||||||
format!("127.0.0.1:{}", socks_port).parse().unwrap();
|
|
||||||
let connector_config = ConnectorConfig {
|
let connector_config = ConnectorConfig {
|
||||||
target_host: "127.0.0.1".to_string(),
|
target_host: "127.0.0.1".to_string(),
|
||||||
target_port: listener_port,
|
target_port: listener_port,
|
||||||
@@ -2883,9 +2858,10 @@ mod tests {
|
|||||||
ca_cert_path: path_arc!(dir.path().join("ca.pem")),
|
ca_cert_path: path_arc!(dir.path().join("ca.pem")),
|
||||||
auth_token: Arc::new(token.clone()),
|
auth_token: Arc::new(token.clone()),
|
||||||
};
|
};
|
||||||
let connector_task = tokio::spawn(async move {
|
let connector_task =
|
||||||
run_connector_with_socks(connector_config, socks_addr).await
|
tokio::spawn(
|
||||||
});
|
async move { run_connector_with_socks(connector_config, socks_addr).await },
|
||||||
|
);
|
||||||
tokio::time::sleep(std::time::Duration::from_millis(400)).await;
|
tokio::time::sleep(std::time::Duration::from_millis(400)).await;
|
||||||
|
|
||||||
// The logs should have been emitted (tracing::info!) by the connector
|
// The logs should have been emitted (tracing::info!) by the connector
|
||||||
@@ -2924,8 +2900,7 @@ mod tests {
|
|||||||
ca_cert_path: path_arc!(dir.path().join("ca.pem")),
|
ca_cert_path: path_arc!(dir.path().join("ca.pem")),
|
||||||
auth_token: Arc::new("secret-token-abc".to_string()),
|
auth_token: Arc::new("secret-token-abc".to_string()),
|
||||||
};
|
};
|
||||||
let listener_task =
|
let listener_task = tokio::spawn(async move { run_listener(listener_config).await });
|
||||||
tokio::spawn(async move { run_listener(listener_config).await });
|
|
||||||
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
|
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
|
||||||
|
|
||||||
// Connect with wrong token
|
// Connect with wrong token
|
||||||
@@ -2939,10 +2914,7 @@ mod tests {
|
|||||||
auth_token: Arc::new(bad_token.to_string()),
|
auth_token: Arc::new(bad_token.to_string()),
|
||||||
};
|
};
|
||||||
let result = connect_tunnel(connector_config).await;
|
let result = connect_tunnel(connector_config).await;
|
||||||
assert!(
|
assert!(result.is_err(), "Bad auth token should fail to connect");
|
||||||
result.is_err(),
|
|
||||||
"Bad auth token should fail to connect"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Verify error message doesn't leak the actual token values
|
// Verify error message doesn't leak the actual token values
|
||||||
let err_msg = result.unwrap_err().to_string();
|
let err_msg = result.unwrap_err().to_string();
|
||||||
|
|||||||
Reference in New Issue
Block a user