mirror of
https://github.com/nushell/nushell
synced 2024-12-26 04:53:09 +00:00
c52884b3c8
# Description The local socket PR introduced a `Waitable` type, which could either hold a value or be waited on until a value is available. Unlike a channel, it would always return that value once set. However, one issue with this design was that there was no way to detect whether a value would ever be written. This splits the writer into a different type `WaitableMut`, so that when it is dropped, waiting threads can fail (because they'll never get a value). # Tests + Formatting A test has been added to `stress_internals` to make sure this fails in the right way. - 🟢 `toolkit fmt` - 🟢 `toolkit clippy` - 🟢 `toolkit test` - 🟢 `toolkit test stdlib`
149 lines
4.2 KiB
Rust
149 lines
4.2 KiB
Rust
use std::{sync::mpsc, time::Duration};
|
|
|
|
use nu_test_support::nu_with_plugins;
|
|
|
|
fn ensure_stress_env_vars_unset() {
|
|
for (key, _) in std::env::vars_os() {
|
|
if key.to_string_lossy().starts_with("STRESS_") {
|
|
panic!("Test is running in a dirty environment: {key:?} is set");
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_stdio() {
|
|
ensure_stress_env_vars_unset();
|
|
let result = nu_with_plugins!(
|
|
cwd: ".",
|
|
plugin: ("nu_plugin_stress_internals"),
|
|
"stress_internals"
|
|
);
|
|
assert!(result.status.success());
|
|
assert!(result.out.contains("local_socket_path: None"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_local_socket() {
|
|
ensure_stress_env_vars_unset();
|
|
let result = nu_with_plugins!(
|
|
cwd: ".",
|
|
envs: vec![
|
|
("STRESS_ADVERTISE_LOCAL_SOCKET", "1"),
|
|
],
|
|
plugin: ("nu_plugin_stress_internals"),
|
|
"stress_internals"
|
|
);
|
|
assert!(result.status.success());
|
|
// Should be run once in stdio mode
|
|
assert!(result.err.contains("--stdio"));
|
|
// And then in local socket mode
|
|
assert!(result.err.contains("--local-socket"));
|
|
assert!(result.out.contains("local_socket_path: Some"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_failing_local_socket_fallback() {
|
|
ensure_stress_env_vars_unset();
|
|
let result = nu_with_plugins!(
|
|
cwd: ".",
|
|
envs: vec![
|
|
("STRESS_ADVERTISE_LOCAL_SOCKET", "1"),
|
|
("STRESS_REFUSE_LOCAL_SOCKET", "1"),
|
|
],
|
|
plugin: ("nu_plugin_stress_internals"),
|
|
"stress_internals"
|
|
);
|
|
assert!(result.status.success());
|
|
|
|
// Count the number of times we do stdio/local socket
|
|
let mut count_stdio = 0;
|
|
let mut count_local_socket = 0;
|
|
|
|
for line in result.err.split('\n') {
|
|
if line.contains("--stdio") {
|
|
count_stdio += 1;
|
|
}
|
|
if line.contains("--local-socket") {
|
|
count_local_socket += 1;
|
|
}
|
|
}
|
|
|
|
// Should be run once in local socket mode
|
|
assert_eq!(1, count_local_socket, "count of --local-socket");
|
|
// Should be run twice in stdio mode, due to the fallback
|
|
assert_eq!(2, count_stdio, "count of --stdio");
|
|
|
|
// In the end it should not be running in local socket mode, but should succeed
|
|
assert!(result.out.contains("local_socket_path: None"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_exit_before_hello_stdio() {
|
|
ensure_stress_env_vars_unset();
|
|
// This can deadlock if not handled properly, so we try several times and timeout
|
|
for _ in 0..5 {
|
|
let (tx, rx) = mpsc::channel();
|
|
std::thread::spawn(move || {
|
|
let result = nu_with_plugins!(
|
|
cwd: ".",
|
|
envs: vec![
|
|
("STRESS_EXIT_BEFORE_HELLO", "1"),
|
|
],
|
|
plugin: ("nu_plugin_stress_internals"),
|
|
"stress_internals"
|
|
);
|
|
let _ = tx.send(result);
|
|
});
|
|
let result = rx
|
|
.recv_timeout(Duration::from_secs(15))
|
|
.expect("timed out. probably a deadlock");
|
|
assert!(!result.status.success());
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_exit_early_stdio() {
|
|
ensure_stress_env_vars_unset();
|
|
let result = nu_with_plugins!(
|
|
cwd: ".",
|
|
envs: vec![
|
|
("STRESS_EXIT_EARLY", "1"),
|
|
],
|
|
plugin: ("nu_plugin_stress_internals"),
|
|
"stress_internals"
|
|
);
|
|
assert!(!result.status.success());
|
|
assert!(result.err.contains("--stdio"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_exit_early_local_socket() {
|
|
ensure_stress_env_vars_unset();
|
|
let result = nu_with_plugins!(
|
|
cwd: ".",
|
|
envs: vec![
|
|
("STRESS_ADVERTISE_LOCAL_SOCKET", "1"),
|
|
("STRESS_EXIT_EARLY", "1"),
|
|
],
|
|
plugin: ("nu_plugin_stress_internals"),
|
|
"stress_internals"
|
|
);
|
|
assert!(!result.status.success());
|
|
assert!(result.err.contains("--local-socket"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_wrong_version() {
|
|
ensure_stress_env_vars_unset();
|
|
let result = nu_with_plugins!(
|
|
cwd: ".",
|
|
envs: vec![
|
|
("STRESS_WRONG_VERSION", "1"),
|
|
],
|
|
plugin: ("nu_plugin_stress_internals"),
|
|
"stress_internals"
|
|
);
|
|
assert!(!result.status.success());
|
|
assert!(result.err.contains("version"));
|
|
assert!(result.err.contains("0.0.0"));
|
|
}
|