write the remaining test fake executables from a child process
This commit is contained in:
parent
41f832458e
commit
d452da09ae
4 changed files with 80 additions and 23 deletions
|
|
@ -64,6 +64,24 @@ mod tests {
|
||||||
sleep 30 >/dev/null 2>&1 &\n\
|
sleep 30 >/dev/null 2>&1 &\n\
|
||||||
wait\n";
|
wait\n";
|
||||||
|
|
||||||
|
/// Write the script `body` to `path` as an executable, from a child process
|
||||||
|
/// rather than from this one: a write fd on it held here could be inherited
|
||||||
|
/// by a child another test thread forks, and exec'ing a file some process
|
||||||
|
/// still holds open for writing fails with `ETXTBSY`.
|
||||||
|
fn write_executable(path: &Path, body: &str) {
|
||||||
|
let status = std::process::Command::new("/bin/sh")
|
||||||
|
.args([
|
||||||
|
"-c",
|
||||||
|
r#"printf '%s' "$1" > "$2" && chmod 755 "$2""#,
|
||||||
|
"sh",
|
||||||
|
body,
|
||||||
|
])
|
||||||
|
.arg(path)
|
||||||
|
.status()
|
||||||
|
.expect("run /bin/sh");
|
||||||
|
assert!(status.success(), "writing {} failed", path.display());
|
||||||
|
}
|
||||||
|
|
||||||
async fn exists(path: &Path) {
|
async fn exists(path: &Path) {
|
||||||
for _ in 0..250 {
|
for _ in 0..250 {
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
|
|
@ -76,12 +94,9 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn a_claude_stop_is_a_sigint_to_the_process() {
|
async fn a_claude_stop_is_a_sigint_to_the_process() {
|
||||||
use std::os::unix::fs::PermissionsExt as _;
|
|
||||||
|
|
||||||
let dir = tempfile::tempdir().unwrap();
|
let dir = tempfile::tempdir().unwrap();
|
||||||
let program = dir.path().join("fake-claude");
|
let program = dir.path().join("fake-claude");
|
||||||
std::fs::write(&program, FAKE_CLAUDE).unwrap();
|
write_executable(&program, FAKE_CLAUDE);
|
||||||
std::fs::set_permissions(&program, std::fs::Permissions::from_mode(0o755)).unwrap();
|
|
||||||
let (ready, mark) = (dir.path().join("ready"), dir.path().join("int"));
|
let (ready, mark) = (dir.path().join("ready"), dir.path().join("int"));
|
||||||
let config = Config {
|
let config = Config {
|
||||||
program: Some(program),
|
program: Some(program),
|
||||||
|
|
|
||||||
|
|
@ -626,23 +626,38 @@ mod tests {
|
||||||
let _ = std::fs::remove_dir_all(config.users_file.parent().unwrap());
|
let _ = std::fs::remove_dir_all(config.users_file.parent().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Write the script `body` to `path` as an executable, from a child process
|
||||||
|
/// rather than from this one: a write fd on it held here could be inherited
|
||||||
|
/// by a child another test thread forks, and exec'ing a file some process
|
||||||
|
/// still holds open for writing fails with `ETXTBSY`.
|
||||||
|
fn write_executable(path: &std::path::Path, body: &str) {
|
||||||
|
let status = std::process::Command::new("/bin/sh")
|
||||||
|
.args([
|
||||||
|
"-c",
|
||||||
|
r#"printf '%s' "$1" > "$2" && chmod 755 "$2""#,
|
||||||
|
"sh",
|
||||||
|
body,
|
||||||
|
])
|
||||||
|
.arg(path)
|
||||||
|
.status()
|
||||||
|
.expect("run /bin/sh");
|
||||||
|
assert!(status.success(), "writing {} failed", path.display());
|
||||||
|
}
|
||||||
|
|
||||||
/// `handle` waits for the `flock` `swarmctl` takes, not only for the
|
/// `handle` waits for the `flock` `swarmctl` takes, not only for the
|
||||||
/// in-process lock: it is held here while `handle` runs with a lock of
|
/// in-process lock: it is held here while `handle` runs with a lock of
|
||||||
/// its own that nothing contends.
|
/// its own that nothing contends.
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn an_identity_request_waits_for_the_users_file_lock() {
|
async fn an_identity_request_waits_for_the_users_file_lock() {
|
||||||
use std::os::unix::fs::PermissionsExt as _;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
let mut config = config_with_one_operator();
|
let mut config = config_with_one_operator();
|
||||||
let dir = config.users_file.parent().unwrap().to_owned();
|
let dir = config.users_file.parent().unwrap().to_owned();
|
||||||
let authelia = dir.join("authelia");
|
let authelia = dir.join("authelia");
|
||||||
std::fs::write(
|
write_executable(
|
||||||
&authelia,
|
&authelia,
|
||||||
"#!/bin/sh\nprintf 'Random Password: pw\\nDigest: $argon2id$x\\n'\n",
|
"#!/bin/sh\nprintf 'Random Password: pw\\nDigest: $argon2id$x\\n'\n",
|
||||||
)
|
);
|
||||||
.unwrap();
|
|
||||||
std::fs::set_permissions(&authelia, std::fs::Permissions::from_mode(0o755)).unwrap();
|
|
||||||
config.authelia_bin = authelia;
|
config.authelia_bin = authelia;
|
||||||
|
|
||||||
let held = crate::store::lock_users_file(&config.users_file, Duration::from_secs(1))
|
let held = crate::store::lock_users_file(&config.users_file, Duration::from_secs(1))
|
||||||
|
|
|
||||||
|
|
@ -355,8 +355,6 @@ fn failed(why: &str, session: Option<&Session>) -> Reply {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) mod tests {
|
pub(crate) mod tests {
|
||||||
use std::os::unix::fs::PermissionsExt as _;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// A stand-in for `claude auth login`: prints a URL, reads a code, and
|
/// A stand-in for `claude auth login`: prints a URL, reads a code, and
|
||||||
|
|
@ -389,9 +387,25 @@ echo "Login successful."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Every stub, written once before any test spawns one: a file still
|
/// Write the script `body` to `path` as an executable, from a child process
|
||||||
/// open for writing in a child another test forked meanwhile cannot be
|
/// rather than from this one: a write fd on it held here could be inherited
|
||||||
/// executed (`ETXTBSY`).
|
/// by a child another test thread forks, and exec'ing a file some process
|
||||||
|
/// still holds open for writing fails with `ETXTBSY`.
|
||||||
|
fn write_executable(path: &Path, body: &str) {
|
||||||
|
let status = std::process::Command::new("/bin/sh")
|
||||||
|
.args([
|
||||||
|
"-c",
|
||||||
|
r#"printf '%s' "$1" > "$2" && chmod 755 "$2""#,
|
||||||
|
"sh",
|
||||||
|
body,
|
||||||
|
])
|
||||||
|
.arg(path)
|
||||||
|
.status()
|
||||||
|
.expect("run /bin/sh");
|
||||||
|
assert!(status.success(), "writing {} failed", path.display());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Every stub, written once before any test spawns one.
|
||||||
pub(crate) fn stubs() -> &'static Path {
|
pub(crate) fn stubs() -> &'static Path {
|
||||||
static DIR: std::sync::OnceLock<PathBuf> = std::sync::OnceLock::new();
|
static DIR: std::sync::OnceLock<PathBuf> = std::sync::OnceLock::new();
|
||||||
DIR.get_or_init(|| {
|
DIR.get_or_init(|| {
|
||||||
|
|
@ -406,10 +420,7 @@ echo "Login successful."
|
||||||
("silent", "#!/bin/sh\nexec sleep 600\n"),
|
("silent", "#!/bin/sh\nexec sleep 600\n"),
|
||||||
("exits", "#!/bin/sh\necho \"not logged in\" >&2\nexit 1\n"),
|
("exits", "#!/bin/sh\necho \"not logged in\" >&2\nexit 1\n"),
|
||||||
] {
|
] {
|
||||||
let stub = dir.join(name);
|
write_executable(&dir.join(name), script);
|
||||||
std::fs::write(&stub, script).expect("stub");
|
|
||||||
std::fs::set_permissions(&stub, std::fs::Permissions::from_mode(0o755))
|
|
||||||
.expect("chmod");
|
|
||||||
}
|
}
|
||||||
dir
|
dir
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1573,6 +1573,24 @@ mod tests {
|
||||||
fs::remove_dir_all(&dir).ok();
|
fs::remove_dir_all(&dir).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Write the script `body` to `path` as an executable, from a child process
|
||||||
|
/// rather than from this one: a write fd on it held here could be inherited
|
||||||
|
/// by a child another test thread forks, and exec'ing a file some process
|
||||||
|
/// still holds open for writing fails with `ETXTBSY`.
|
||||||
|
fn write_executable(path: &std::path::Path, body: &str) {
|
||||||
|
let status = std::process::Command::new("/bin/sh")
|
||||||
|
.args([
|
||||||
|
"-c",
|
||||||
|
r#"printf '%s' "$1" > "$2" && chmod 755 "$2""#,
|
||||||
|
"sh",
|
||||||
|
body,
|
||||||
|
])
|
||||||
|
.arg(path)
|
||||||
|
.status()
|
||||||
|
.expect("run /bin/sh");
|
||||||
|
assert!(status.success(), "writing {} failed", path.display());
|
||||||
|
}
|
||||||
|
|
||||||
/// A scratch directory holding a `users.yml` with one user, `carol`, and
|
/// A scratch directory holding a `users.yml` with one user, `carol`, and
|
||||||
/// a stand-in `authelia` that takes `delay` seconds to mint a password.
|
/// a stand-in `authelia` that takes `delay` seconds to mint a password.
|
||||||
fn locked_users_fixture(tag: &str, delay: &str) -> Paths {
|
fn locked_users_fixture(tag: &str, delay: &str) -> Paths {
|
||||||
|
|
@ -1580,14 +1598,12 @@ mod tests {
|
||||||
let _ = fs::remove_dir_all(&dir);
|
let _ = fs::remove_dir_all(&dir);
|
||||||
fs::create_dir_all(&dir).expect("temp dir");
|
fs::create_dir_all(&dir).expect("temp dir");
|
||||||
let authelia_bin = dir.join("authelia");
|
let authelia_bin = dir.join("authelia");
|
||||||
fs::write(
|
write_executable(
|
||||||
&authelia_bin,
|
&authelia_bin,
|
||||||
format!(
|
&format!(
|
||||||
"#!/bin/sh\nsleep {delay}\nprintf 'Random Password: pw\\nDigest: $argon2id$x\\n'\n"
|
"#!/bin/sh\nsleep {delay}\nprintf 'Random Password: pw\\nDigest: $argon2id$x\\n'\n"
|
||||||
),
|
),
|
||||||
)
|
);
|
||||||
.expect("fake authelia");
|
|
||||||
fs::set_permissions(&authelia_bin, Permissions::from_mode(0o755)).expect("chmod");
|
|
||||||
let users_file = dir.join("users.yml");
|
let users_file = dir.join("users.yml");
|
||||||
fs::write(
|
fs::write(
|
||||||
&users_file,
|
&users_file,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue