Public release release-6756e5208c8b
Source commit: 6756e5208c8b79e83d55610251430bc1baef53a3 Public tree identity: sha256:2f58837c3759b4f466cbc274571ee71bc0d24c7552dc009c186394e99123da87
This commit is contained in:
commit
18cba9c609
210 changed files with 78616 additions and 0 deletions
205
crates/clusterflux-node/src/assignment_runner/tests.rs
Normal file
205
crates/clusterflux-node/src/assignment_runner/tests.rs
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
use std::io::{BufRead, BufReader, Write};
|
||||
use std::net::TcpListener;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use super::*;
|
||||
|
||||
fn start_running_control_server() -> (String, thread::JoinHandle<()>) {
|
||||
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
let coordinator = listener.local_addr().unwrap().to_string();
|
||||
let server = thread::spawn(move || {
|
||||
let (mut stream, _) = listener.accept().unwrap();
|
||||
let mut reader = BufReader::new(stream.try_clone().unwrap());
|
||||
loop {
|
||||
let mut request = String::new();
|
||||
match reader.read_line(&mut request) {
|
||||
Ok(0) | Err(_) => break,
|
||||
Ok(_) => stream
|
||||
.write_all(b"{\"type\":\"task_control\",\"process\":\"vp\",\"task\":\"task\",\"cancel_requested\":false,\"abort_requested\":false}\n")
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
});
|
||||
(coordinator, server)
|
||||
}
|
||||
|
||||
fn test_controlled_runner(
|
||||
coordinator: String,
|
||||
timeout: Duration,
|
||||
) -> CoordinatorControlledProcessRunner {
|
||||
CoordinatorControlledProcessRunner {
|
||||
args: Args {
|
||||
coordinator,
|
||||
tenant: "tenant".to_owned(),
|
||||
project: "project".to_owned(),
|
||||
project_root: None,
|
||||
node: "node".to_owned(),
|
||||
enrollment_grant: None,
|
||||
public_key: None,
|
||||
control_poll_ms: 0,
|
||||
assignment_poll_ms: 1,
|
||||
emit_ready: false,
|
||||
worker: true,
|
||||
},
|
||||
process: "vp".to_owned(),
|
||||
task: "task".to_owned(),
|
||||
node_private_key: clusterflux_core::derive_ed25519_private_key_from_seed(
|
||||
"controlled-runner-test",
|
||||
),
|
||||
debug_control: Arc::new(WasmDebugControl::default()),
|
||||
command_status: Arc::new(Mutex::new(None)),
|
||||
timeout,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn controlled_process_runner_kills_running_group_when_abort_is_polled() {
|
||||
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
let coordinator = listener.local_addr().unwrap().to_string();
|
||||
let server = thread::spawn(move || {
|
||||
let (mut stream, _) = listener.accept().unwrap();
|
||||
let mut request = String::new();
|
||||
BufReader::new(stream.try_clone().unwrap())
|
||||
.read_line(&mut request)
|
||||
.unwrap();
|
||||
assert!(!request.trim().is_empty());
|
||||
stream
|
||||
.write_all(b"{\"type\":\"task_control\",\"process\":\"vp\",\"task\":\"task\",\"cancel_requested\":false,\"abort_requested\":true}\n")
|
||||
.unwrap();
|
||||
});
|
||||
let mut runner = CoordinatorControlledProcessRunner {
|
||||
args: Args {
|
||||
coordinator,
|
||||
tenant: "tenant".to_owned(),
|
||||
project: "project".to_owned(),
|
||||
project_root: None,
|
||||
node: "node".to_owned(),
|
||||
enrollment_grant: None,
|
||||
public_key: None,
|
||||
control_poll_ms: 0,
|
||||
assignment_poll_ms: 1,
|
||||
emit_ready: false,
|
||||
worker: true,
|
||||
},
|
||||
process: "vp".to_owned(),
|
||||
task: "task".to_owned(),
|
||||
node_private_key: clusterflux_core::derive_ed25519_private_key_from_seed(
|
||||
"controlled-runner-test",
|
||||
),
|
||||
debug_control: Arc::new(WasmDebugControl::default()),
|
||||
command_status: Arc::new(Mutex::new(None)),
|
||||
timeout: Duration::from_secs(30),
|
||||
};
|
||||
let started = Instant::now();
|
||||
let error = runner
|
||||
.run(&PodmanCommand {
|
||||
program: "sh".to_owned(),
|
||||
args: vec!["-c".to_owned(), "sleep 30 & wait".to_owned()],
|
||||
})
|
||||
.unwrap_err();
|
||||
server.join().unwrap();
|
||||
|
||||
assert!(matches!(error, BackendError::Cancelled(_)));
|
||||
assert!(started.elapsed() < Duration::from_secs(5));
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn command_timeout_is_bounded_and_a_later_command_still_runs() {
|
||||
let (coordinator, server) = start_running_control_server();
|
||||
let mut runner = test_controlled_runner(coordinator, Duration::from_millis(120));
|
||||
let started = Instant::now();
|
||||
let error = runner
|
||||
.run(&PodmanCommand {
|
||||
program: "sh".to_owned(),
|
||||
args: vec!["-c".to_owned(), "sleep 30 & wait".to_owned()],
|
||||
})
|
||||
.unwrap_err();
|
||||
assert!(error.to_string().contains("timeout"));
|
||||
assert!(started.elapsed() < Duration::from_secs(5));
|
||||
drop(runner);
|
||||
server.join().unwrap();
|
||||
|
||||
let (coordinator, server) = start_running_control_server();
|
||||
let mut runner = test_controlled_runner(coordinator, Duration::from_secs(5));
|
||||
let output = runner
|
||||
.run(&PodmanCommand {
|
||||
program: "sh".to_owned(),
|
||||
args: vec!["-c".to_owned(), "printf healthy".to_owned()],
|
||||
})
|
||||
.unwrap();
|
||||
assert_eq!(output.status_code, Some(0));
|
||||
assert_eq!(String::from_utf8(output.stdout).unwrap(), "healthy");
|
||||
drop(runner);
|
||||
server.join().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn command_source_verification_rejects_a_changed_checkout() {
|
||||
let checkout = tempfile::tempdir().unwrap();
|
||||
std::fs::write(checkout.path().join("source.c"), "int value = 1;\n").unwrap();
|
||||
let expected = snapshot_project(checkout.path()).unwrap().digest;
|
||||
verify_source_snapshot(checkout.path(), &expected).unwrap();
|
||||
|
||||
std::fs::write(checkout.path().join("source.c"), "int value = 2;\n").unwrap();
|
||||
let error = verify_source_snapshot(checkout.path(), &expected).unwrap_err();
|
||||
|
||||
assert!(error.contains("source snapshot mismatch"));
|
||||
assert!(error.contains(expected.as_str()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn command_environment_verification_rejects_a_changed_recipe() {
|
||||
let checkout = tempfile::tempdir().unwrap();
|
||||
let environment = checkout.path().join("envs/linux");
|
||||
std::fs::create_dir_all(&environment).unwrap();
|
||||
std::fs::write(
|
||||
environment.join("Containerfile"),
|
||||
"FROM docker.io/library/alpine:3.20\n",
|
||||
)
|
||||
.unwrap();
|
||||
let expected = clusterflux_core::discover_environments(checkout.path())
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.find(|environment| environment.name == "linux")
|
||||
.unwrap()
|
||||
.digest;
|
||||
verify_environment_digest(checkout.path(), "linux", &expected).unwrap();
|
||||
|
||||
std::fs::write(
|
||||
environment.join("Containerfile"),
|
||||
"FROM docker.io/library/alpine:3.21\n",
|
||||
)
|
||||
.unwrap();
|
||||
let error = verify_environment_digest(checkout.path(), "linux", &expected).unwrap_err();
|
||||
|
||||
assert!(error.contains("does not match the bundle"));
|
||||
assert!(error.contains(expected.as_str()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn configured_secret_values_are_redacted_before_guest_or_coordinator_logging() {
|
||||
assert!(is_secret_environment_name("API_TOKEN"));
|
||||
assert!(is_secret_environment_name("database_password"));
|
||||
assert!(!is_secret_environment_name("SOURCE_DATE_EPOCH"));
|
||||
assert_eq!(
|
||||
redact_configured_values(
|
||||
"token=correct-horse and again correct-horse".to_owned(),
|
||||
&["correct-horse".to_owned()],
|
||||
),
|
||||
"token=[REDACTED] and again [REDACTED]"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn native_command_requires_environment_and_network_grant() {
|
||||
let error = require_command_environment(None).unwrap_err();
|
||||
assert!(error.contains("explicit command-capable environment"));
|
||||
assert_eq!(require_command_environment(Some("linux")).unwrap(), "linux");
|
||||
|
||||
authorize_command_network(&clusterflux_core::CommandNetworkPolicy::Disabled, false).unwrap();
|
||||
let error = authorize_command_network(&clusterflux_core::CommandNetworkPolicy::Enabled, false)
|
||||
.unwrap_err();
|
||||
assert!(error.contains("Network capability"));
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue