CI fixes
This commit is contained in:
parent
b6689a3927
commit
146583d32a
|
|
@ -61,7 +61,7 @@ jobs:
|
||||||
- uses: dtolnay/rust-toolchain@stable
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
- uses: Swatinem/rust-cache@v2
|
- uses: Swatinem/rust-cache@v2
|
||||||
- name: perf, memory, and 30s fuzz gates
|
- name: perf, memory, and 30s fuzz gates
|
||||||
run: cargo test --release --test acceptance -- --ignored --nocapture
|
run: cargo test --release --test acceptance -- --ignored --nocapture --test-threads=1
|
||||||
|
|
||||||
m4-perf-gates:
|
m4-perf-gates:
|
||||||
name: M4 Perf Gates
|
name: M4 Perf Gates
|
||||||
|
|
@ -71,7 +71,7 @@ jobs:
|
||||||
- uses: dtolnay/rust-toolchain@stable
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
- uses: Swatinem/rust-cache@v2
|
- uses: Swatinem/rust-cache@v2
|
||||||
- name: tree-sitter parse + highlight latency budgets
|
- name: tree-sitter parse + highlight latency budgets
|
||||||
run: cargo test --release --test m4_acceptance -- --ignored --nocapture
|
run: cargo test --release --test m4_acceptance -- --ignored --nocapture --test-threads=1
|
||||||
|
|
||||||
# m5-perf-gates: luajit-only by design.
|
# m5-perf-gates: luajit-only by design.
|
||||||
# The keystroke-to-render gate measures protocol-path latency (Unix
|
# The keystroke-to-render gate measures protocol-path latency (Unix
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,18 @@ fn daemon_debug_enabled() -> bool {
|
||||||
std::env::var_os(PMACS_ATTACH_DEBUG).is_some_and(|v| !v.is_empty() && v != "0")
|
std::env::var_os(PMACS_ATTACH_DEBUG).is_some_and(|v| !v.is_empty() && v != "0")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
|
fn peer_uid(stream: &UnixStream) -> Option<u32> {
|
||||||
|
nix::sys::socket::getsockopt(stream, nix::sys::socket::sockopt::PeerCredentials)
|
||||||
|
.ok()
|
||||||
|
.map(|cred| cred.uid())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||||
|
fn peer_uid(_stream: &UnixStream) -> Option<u32> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn daemon_debug(msg: impl AsRef<str>) {
|
fn daemon_debug(msg: impl AsRef<str>) {
|
||||||
if daemon_debug_enabled() {
|
if daemon_debug_enabled() {
|
||||||
eprintln!("pmacs daemon debug: {}", msg.as_ref());
|
eprintln!("pmacs daemon debug: {}", msg.as_ref());
|
||||||
|
|
@ -698,15 +710,12 @@ fn per_attach_thread(
|
||||||
// reconnect → same color slot. If SO_PEERCRED fails (e.g.,
|
// reconnect → same color slot. If SO_PEERCRED fails (e.g.,
|
||||||
// non-Unix peer, kernel API unavailable), fall back to a
|
// non-Unix peer, kernel API unavailable), fall back to a
|
||||||
// per-FrontendId slot (degrades to per-connection stability).
|
// per-FrontendId slot (degrades to per-connection stability).
|
||||||
let color_slot =
|
let color_slot = if let Some(uid) = peer_uid(&stream) {
|
||||||
match nix::sys::socket::getsockopt(&stream, nix::sys::socket::sockopt::PeerCredentials) {
|
daemon_state.color_slot_for_uid(uid)
|
||||||
Ok(cred) => daemon_state.color_slot_for_uid(cred.uid()),
|
} else {
|
||||||
Err(_) => {
|
|
||||||
// Fallback: use frontend_id-based slot; per-connection
|
// Fallback: use frontend_id-based slot; per-connection
|
||||||
// stability only (no cross-reconnect within session).
|
// stability only (no cross-reconnect within session).
|
||||||
u8::try_from(frontend_id.0 % (crate::overlay_color::PALETTE_LEN as u64))
|
u8::try_from(frontend_id.0 % (crate::overlay_color::PALETTE_LEN as u64)).unwrap_or(0)
|
||||||
.unwrap_or(0)
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let session_state =
|
let session_state =
|
||||||
|
|
|
||||||
|
|
@ -389,7 +389,7 @@ const READER_SEND_POLL_INTERVAL: Duration = Duration::from_millis(50);
|
||||||
/// parser worker may still have already-read bytes in flight. This is
|
/// parser worker may still have already-read bytes in flight. This is
|
||||||
/// not process termination grace; it is only the final output flush
|
/// not process termination grace; it is only the final output flush
|
||||||
/// before the runtime handles are dropped.
|
/// before the runtime handles are dropped.
|
||||||
const EXIT_OUTPUT_DRAIN_TIMEOUT: Duration = Duration::from_millis(250);
|
const EXIT_OUTPUT_DRAIN_TIMEOUT: Duration = Duration::from_secs(2);
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Supervisor
|
// Supervisor
|
||||||
|
|
|
||||||
|
|
@ -294,10 +294,18 @@ fn cli_attach_invokes_test_ssh_with_expected_argv() {
|
||||||
});
|
});
|
||||||
let lines: Vec<&str> = argv.lines().collect();
|
let lines: Vec<&str> = argv.lines().collect();
|
||||||
// build_ssh_command for `ssh:mac-studio` (no user, no instance)
|
// build_ssh_command for `ssh:mac-studio` (no user, no instance)
|
||||||
// emits `[-T, host, "pmacs", "--daemon-attach"]`.
|
// defaults to the stderr protocol channel and advertises the
|
||||||
|
// remote fd through env.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
lines,
|
lines,
|
||||||
vec!["-T", "mac-studio", "pmacs", "--daemon-attach"],
|
vec![
|
||||||
|
"-T",
|
||||||
|
"mac-studio",
|
||||||
|
"env",
|
||||||
|
"PMACS_ATTACH_PROTOCOL_FD=2",
|
||||||
|
"pmacs",
|
||||||
|
"--daemon-attach",
|
||||||
|
],
|
||||||
"argv shape: {lines:?}"
|
"argv shape: {lines:?}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -330,6 +338,8 @@ fn cli_attach_with_user_and_instance_name_passes_through_dash_l_and_dash_dash_so
|
||||||
"-l",
|
"-l",
|
||||||
"alice",
|
"alice",
|
||||||
"workstation",
|
"workstation",
|
||||||
|
"env",
|
||||||
|
"PMACS_ATTACH_PROTOCOL_FD=2",
|
||||||
"pmacs",
|
"pmacs",
|
||||||
"--daemon-attach",
|
"--daemon-attach",
|
||||||
"--socket",
|
"--socket",
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,8 @@ use pmacs::protocol::{
|
||||||
mod common;
|
mod common;
|
||||||
use common::pty::spawn_pmacs_in_pty;
|
use common::pty::spawn_pmacs_in_pty;
|
||||||
|
|
||||||
|
const PMACS_ATTACH_SSH_PROTOCOL: &str = "PMACS_ATTACH_SSH_PROTOCOL";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Helpers
|
// Helpers
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
@ -145,6 +147,7 @@ fn handshake_retry_cap_fires_after_three_failed_handshakes() {
|
||||||
let output = Command::new(env!("CARGO_BIN_EXE_pmacs"))
|
let output = Command::new(env!("CARGO_BIN_EXE_pmacs"))
|
||||||
.args(["--attach", "host"])
|
.args(["--attach", "host"])
|
||||||
.env(PMACS_TEST_SSH_BIN, &fake_ssh)
|
.env(PMACS_TEST_SSH_BIN, &fake_ssh)
|
||||||
|
.env(PMACS_ATTACH_SSH_PROTOCOL, "stdout")
|
||||||
.env(PMACS_TEST_BACKOFF_SCALE_MS, "1")
|
.env(PMACS_TEST_BACKOFF_SCALE_MS, "1")
|
||||||
.env("HOME", isolated_home)
|
.env("HOME", isolated_home)
|
||||||
.env("XDG_CONFIG_HOME", isolated_home)
|
.env("XDG_CONFIG_HOME", isolated_home)
|
||||||
|
|
@ -261,6 +264,7 @@ fn ssh_stderr_from_handshake_attempts_reaches_user() {
|
||||||
let output = Command::new(env!("CARGO_BIN_EXE_pmacs"))
|
let output = Command::new(env!("CARGO_BIN_EXE_pmacs"))
|
||||||
.args(["--attach", "host"])
|
.args(["--attach", "host"])
|
||||||
.env(PMACS_TEST_SSH_BIN, &fake_ssh)
|
.env(PMACS_TEST_SSH_BIN, &fake_ssh)
|
||||||
|
.env(PMACS_ATTACH_SSH_PROTOCOL, "stdout")
|
||||||
.env(PMACS_TEST_BACKOFF_SCALE_MS, "1")
|
.env(PMACS_TEST_BACKOFF_SCALE_MS, "1")
|
||||||
.env("HOME", isolated_home)
|
.env("HOME", isolated_home)
|
||||||
.env("XDG_CONFIG_HOME", isolated_home)
|
.env("XDG_CONFIG_HOME", isolated_home)
|
||||||
|
|
@ -438,6 +442,7 @@ fn ssh_dies_mid_pump_then_reconnect_succeeds() {
|
||||||
&["--attach", "host"],
|
&["--attach", "host"],
|
||||||
&[
|
&[
|
||||||
(PMACS_TEST_SSH_BIN, fx.fake_ssh.as_path()),
|
(PMACS_TEST_SSH_BIN, fx.fake_ssh.as_path()),
|
||||||
|
(PMACS_ATTACH_SSH_PROTOCOL, Path::new("stdout")),
|
||||||
(PMACS_TEST_BACKOFF_SCALE_MS, Path::new("1")),
|
(PMACS_TEST_BACKOFF_SCALE_MS, Path::new("1")),
|
||||||
("HOME", fx.isolated_home.as_path()),
|
("HOME", fx.isolated_home.as_path()),
|
||||||
("XDG_CONFIG_HOME", fx.isolated_home.as_path()),
|
("XDG_CONFIG_HOME", fx.isolated_home.as_path()),
|
||||||
|
|
@ -489,6 +494,7 @@ fn ctrl_c_during_reconnect_sleep_yields_clean_exit() {
|
||||||
&["--attach", "host"],
|
&["--attach", "host"],
|
||||||
&[
|
&[
|
||||||
(PMACS_TEST_SSH_BIN, fx.fake_ssh.as_path()),
|
(PMACS_TEST_SSH_BIN, fx.fake_ssh.as_path()),
|
||||||
|
(PMACS_ATTACH_SSH_PROTOCOL, Path::new("stdout")),
|
||||||
(PMACS_TEST_BACKOFF_SCALE_MS, Path::new("1000")),
|
(PMACS_TEST_BACKOFF_SCALE_MS, Path::new("1000")),
|
||||||
("HOME", fx.isolated_home.as_path()),
|
("HOME", fx.isolated_home.as_path()),
|
||||||
("XDG_CONFIG_HOME", fx.isolated_home.as_path()),
|
("XDG_CONFIG_HOME", fx.isolated_home.as_path()),
|
||||||
|
|
|
||||||
|
|
@ -32,11 +32,17 @@
|
||||||
use pmacs::editor::EditorState;
|
use pmacs::editor::EditorState;
|
||||||
use std::fmt::Write as _;
|
use std::fmt::Write as _;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Mutex;
|
use std::sync::{Mutex, MutexGuard};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
static PUMP_TEST_LOCK: Mutex<()> = Mutex::new(());
|
static PUMP_TEST_LOCK: Mutex<()> = Mutex::new(());
|
||||||
|
|
||||||
|
fn pump_test_guard() -> MutexGuard<'static, ()> {
|
||||||
|
PUMP_TEST_LOCK
|
||||||
|
.lock()
|
||||||
|
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||||
|
}
|
||||||
|
|
||||||
/// Locate a shell binary for tests that require one. Returns the
|
/// Locate a shell binary for tests that require one. Returns the
|
||||||
/// resolved path or `None` if the shell is neither at `PMACS_TEST_<NAME>`
|
/// resolved path or `None` if the shell is neither at `PMACS_TEST_<NAME>`
|
||||||
/// nor on `PATH`. Per-test selective skipping (rather than skipping
|
/// nor on `PATH`. Per-test selective skipping (rather than skipping
|
||||||
|
|
@ -70,6 +76,7 @@ fn locate_shell(name: &str) -> Option<PathBuf> {
|
||||||
|
|
||||||
/// Construct a fresh editor and run the given Lua chunk against it.
|
/// Construct a fresh editor and run the given Lua chunk against it.
|
||||||
fn run(chunk: &str) {
|
fn run(chunk: &str) {
|
||||||
|
let _guard = pump_test_guard();
|
||||||
let mut editor = EditorState::new();
|
let mut editor = EditorState::new();
|
||||||
editor
|
editor
|
||||||
.lua_host
|
.lua_host
|
||||||
|
|
@ -84,7 +91,7 @@ fn run(chunk: &str) {
|
||||||
/// `poll_until` pattern but routes through `tick_processes` so the M6.5
|
/// `poll_until` pattern but routes through `tick_processes` so the M6.5
|
||||||
/// after-tick contract is exercised end-to-end.
|
/// after-tick contract is exercised end-to-end.
|
||||||
fn run_with_pump(setup_chunk: &str, predicate_chunk: &str, timeout_ms: u64) {
|
fn run_with_pump(setup_chunk: &str, predicate_chunk: &str, timeout_ms: u64) {
|
||||||
let _guard = PUMP_TEST_LOCK.lock().expect("pump test lock");
|
let _guard = pump_test_guard();
|
||||||
let mut editor = EditorState::new();
|
let mut editor = EditorState::new();
|
||||||
editor
|
editor
|
||||||
.lua_host
|
.lua_host
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue