|
|
@@ -23,8 +23,26 @@ index=0
|
|
|
|
if [ "${args[0]:-}" = -L ]; then index=2; fi
|
|
|
|
if [ "${args[0]:-}" = -L ]; then index=2; fi
|
|
|
|
case "${args[$index]:-}" in
|
|
|
|
case "${args[$index]:-}" in
|
|
|
|
has-session)
|
|
|
|
has-session)
|
|
|
|
|
|
|
|
# The holder always answers. MOSAIC_TEST_HELD_SESSIONS lets a case add
|
|
|
|
|
|
|
|
# other targets that should answer too — without it there is no way to
|
|
|
|
|
|
|
|
# model "tmux still reports the session" for a non-holder agent, and the
|
|
|
|
|
|
|
|
# launcher's pane-pid-unresolved branch is unreachable from this harness.
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
# A listed target answers only AFTER new-session, because the launcher asks
|
|
|
|
|
|
|
|
# this question twice about the same name: once before launching, where a
|
|
|
|
|
|
|
|
# yes means "already running, nothing to do, exit 0", and once after, where
|
|
|
|
|
|
|
|
# a yes means "the session survived". A shim that answered yes to both
|
|
|
|
|
|
|
|
# would short-circuit at the first and never reach the branch under test —
|
|
|
|
|
|
|
|
# it would look like coverage and measure the idempotency path instead.
|
|
|
|
for argument in "${args[@]}"; do
|
|
|
|
for argument in "${args[@]}"; do
|
|
|
|
[ "$argument" = '=_holder:0.0' ] && exit 0
|
|
|
|
[ "$argument" = '=_holder:0.0' ] && exit 0
|
|
|
|
|
|
|
|
case " ${MOSAIC_TEST_HELD_SESSIONS:-} " in
|
|
|
|
|
|
|
|
*" $argument "*)
|
|
|
|
|
|
|
|
if tr '\0' '\n' < "${MOSAIC_TEST_TMUX_CALLS:?}" | grep -qxF new-session; then
|
|
|
|
|
|
|
|
exit 0
|
|
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
;;
|
|
|
|
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
done
|
|
|
|
exit 1
|
|
|
|
exit 1
|
|
|
|
;;
|
|
|
|
;;
|
|
|
@@ -62,6 +80,30 @@ env -0 > "${MOSAIC_HOME:?}/fleet/pane-environment"
|
|
|
|
SHIM
|
|
|
|
SHIM
|
|
|
|
chmod +x "$FAKE_BIN/mosaic"
|
|
|
|
chmod +x "$FAKE_BIN/mosaic"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# The runtime the rosters below name. The launcher resolves it against PANE_PATH
|
|
|
|
|
|
|
|
# before spawning (#1241), so it has to exist somewhere the pane would find it —
|
|
|
|
|
|
|
|
# not merely on the launcher's own PATH.
|
|
|
|
|
|
|
|
printf '#!/usr/bin/env bash\nexit 0\n' > "$FAKE_BIN/pi"
|
|
|
|
|
|
|
|
chmod +x "$FAKE_BIN/pi"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# PANE_PATH is derived partly from `npm config get prefix`. Left to the real npm
|
|
|
|
|
|
|
|
# it would splice whatever the host has installed into the path under test, and
|
|
|
|
|
|
|
|
# the missing-binary cases below would pass or fail by accident of the machine.
|
|
|
|
|
|
|
|
cat > "$FAKE_BIN/npm" <<'SHIM'
|
|
|
|
|
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
|
|
|
printf '%s\n' "${MOSAIC_TEST_NPM_PREFIX:-/nonexistent}"
|
|
|
|
|
|
|
|
SHIM
|
|
|
|
|
|
|
|
chmod +x "$FAKE_BIN/npm"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# PANE_PATH always ends in the system path. A host that installs these there can
|
|
|
|
|
|
|
|
# not measure the missing-binary cases at all, and a green run would mean
|
|
|
|
|
|
|
|
# nothing — so say so instead of passing.
|
|
|
|
|
|
|
|
for host_binary in mosaic pi; do
|
|
|
|
|
|
|
|
if PATH=/usr/local/bin:/usr/bin:/bin command -v "$host_binary" >/dev/null 2>&1; then
|
|
|
|
|
|
|
|
fail "host provides '$host_binary' in the system path; missing-binary cases are not measurable here"
|
|
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
|
|
write_generated() {
|
|
|
|
write_generated() {
|
|
|
|
local home="$1"
|
|
|
|
local home="$1"
|
|
|
|
local agent="$2"
|
|
|
|
local agent="$2"
|
|
|
@@ -81,6 +123,19 @@ MOSAIC_TMUX_SOCKET=mosaic-test
|
|
|
|
EOF
|
|
|
|
EOF
|
|
|
|
chmod 600 "$home/fleet/agents/$agent.env.generated"
|
|
|
|
chmod 600 "$home/fleet/agents/$agent.env.generated"
|
|
|
|
mkdir -p "$home/work"
|
|
|
|
mkdir -p "$home/work"
|
|
|
|
|
|
|
|
install_pane_binaries "$home"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# `$PANE_HOME/.npm-global/bin` is one of the prefixes the launcher folds into
|
|
|
|
|
|
|
|
# PANE_PATH, so this is the pane's own view of "installed", distinct from the
|
|
|
|
|
|
|
|
# launcher's PATH. Tests that need a binary *absent* remove it from here.
|
|
|
|
|
|
|
|
install_pane_binaries() {
|
|
|
|
|
|
|
|
local pane_home="$1"
|
|
|
|
|
|
|
|
mkdir -p "$pane_home/.npm-global/bin"
|
|
|
|
|
|
|
|
local binary
|
|
|
|
|
|
|
|
for binary in mosaic pi; do
|
|
|
|
|
|
|
|
ln -sf "$FAKE_BIN/$binary" "$pane_home/.npm-global/bin/$binary"
|
|
|
|
|
|
|
|
done
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
run_start() {
|
|
|
|
run_start() {
|
|
|
@@ -88,6 +143,7 @@ run_start() {
|
|
|
|
local agent="$2"
|
|
|
|
local agent="$2"
|
|
|
|
HOME="$home" PATH="$FAKE_BIN:$PATH" MOSAIC_TEST_TMUX_CALLS="$TMUX_CALLS" \
|
|
|
|
HOME="$home" PATH="$FAKE_BIN:$PATH" MOSAIC_TEST_TMUX_CALLS="$TMUX_CALLS" \
|
|
|
|
MOSAIC_TEST_PANE_PID="${MOSAIC_TEST_PANE_PID:-}" \
|
|
|
|
MOSAIC_TEST_PANE_PID="${MOSAIC_TEST_PANE_PID:-}" \
|
|
|
|
|
|
|
|
MOSAIC_TEST_HELD_SESSIONS="${MOSAIC_TEST_HELD_SESSIONS:-}" \
|
|
|
|
MOSAIC_TEST_HOME="$home" \
|
|
|
|
MOSAIC_TEST_HOME="$home" \
|
|
|
|
MOSAIC_TEST_FLEET_OWNER=123e4567-e89b-12d3-a456-426614174000 \
|
|
|
|
MOSAIC_TEST_FLEET_OWNER=123e4567-e89b-12d3-a456-426614174000 \
|
|
|
|
MOSAIC_HOME="$home" "$START" "$agent"
|
|
|
|
MOSAIC_HOME="$home" "$START" "$agent"
|
|
|
@@ -98,7 +154,10 @@ run_start() {
|
|
|
|
HOME_VALID="$ROOT/valid"
|
|
|
|
HOME_VALID="$ROOT/valid"
|
|
|
|
AGENT_VALID="coder0"
|
|
|
|
AGENT_VALID="coder0"
|
|
|
|
write_generated "$HOME_VALID" "$AGENT_VALID"
|
|
|
|
write_generated "$HOME_VALID" "$AGENT_VALID"
|
|
|
|
run_start "$HOME_VALID" "$AGENT_VALID"
|
|
|
|
# A live pane PID is part of what "valid launch" means. Until #1241 this case
|
|
|
|
|
|
|
|
# ran with none, so the suite's one success path was itself a dead pane the
|
|
|
|
|
|
|
|
# launcher reported as fine.
|
|
|
|
|
|
|
|
MOSAIC_TEST_PANE_PID=$$ run_start "$HOME_VALID" "$AGENT_VALID"
|
|
|
|
valid_args=$(tr '\0' '\n' < "$TMUX_CALLS")
|
|
|
|
valid_args=$(tr '\0' '\n' < "$TMUX_CALLS")
|
|
|
|
echo "$valid_args" | grep -qF new-session || fail "valid generated projection did not reach tmux"
|
|
|
|
echo "$valid_args" | grep -qF new-session || fail "valid generated projection did not reach tmux"
|
|
|
|
echo "$valid_args" | grep -qF 'mosaic' || fail "fixed mosaic launcher command missing"
|
|
|
|
echo "$valid_args" | grep -qF 'mosaic' || fail "fixed mosaic launcher command missing"
|
|
|
@@ -245,6 +304,13 @@ PANE_BASH_ENV="$ROOT/pane-boundary.bash-env"
|
|
|
|
printf 'MOSAIC_RUNTIME_BIN=%s\n' "$FAKE_BIN" > \
|
|
|
|
printf 'MOSAIC_RUNTIME_BIN=%s\n' "$FAKE_BIN" > \
|
|
|
|
"$HOME_PANE_BOUNDARY/fleet/agents/coder-pane-boundary.env.local"
|
|
|
|
"$HOME_PANE_BOUNDARY/fleet/agents/coder-pane-boundary.env.local"
|
|
|
|
chmod 600 "$HOME_PANE_BOUNDARY/fleet/agents/coder-pane-boundary.env.local"
|
|
|
|
chmod 600 "$HOME_PANE_BOUNDARY/fleet/agents/coder-pane-boundary.env.local"
|
|
|
|
|
|
|
|
# This case does not go through run_start, so its pane binaries come from
|
|
|
|
|
|
|
|
# MOSAIC_RUNTIME_BIN=$FAKE_BIN in the env.local written above — not from the
|
|
|
|
|
|
|
|
# symlinks install_pane_binaries planted under the generated home, which this
|
|
|
|
|
|
|
|
# launcher never consults because HOME here is the trusted parent. That is a
|
|
|
|
|
|
|
|
# legitimate resolution path, but it means dropping MOSAIC_RUNTIME_BIN from
|
|
|
|
|
|
|
|
# this case on the belief that the symlinks cover it would break the #1241
|
|
|
|
|
|
|
|
# binary check rather than exercise it.
|
|
|
|
LD_PRELOAD='/not/loaded/by-clean-bootstrap.so' \
|
|
|
|
LD_PRELOAD='/not/loaded/by-clean-bootstrap.so' \
|
|
|
|
BASH_ENV="$PANE_BASH_ENV" \
|
|
|
|
BASH_ENV="$PANE_BASH_ENV" \
|
|
|
|
MOSAIC_UNTRUSTED_SENTINEL='must-not-reach-pane' \
|
|
|
|
MOSAIC_UNTRUSTED_SENTINEL='must-not-reach-pane' \
|
|
|
@@ -258,6 +324,7 @@ PATH="$PANE_STALE_PATH" \
|
|
|
|
"MOSAIC_TEST_HOME=$PANE_TRUSTED_HOME" \
|
|
|
|
"MOSAIC_TEST_HOME=$PANE_TRUSTED_HOME" \
|
|
|
|
MOSAIC_TEST_FLEET_OWNER=123e4567-e89b-12d3-a456-426614174000 \
|
|
|
|
MOSAIC_TEST_FLEET_OWNER=123e4567-e89b-12d3-a456-426614174000 \
|
|
|
|
MOSAIC_TEST_EXECUTE_PANE=1 \
|
|
|
|
MOSAIC_TEST_EXECUTE_PANE=1 \
|
|
|
|
|
|
|
|
"MOSAIC_TEST_PANE_PID=$$" \
|
|
|
|
"$START" coder-pane-boundary
|
|
|
|
"$START" coder-pane-boundary
|
|
|
|
pane_args=$(tr '\0' '\n' < "$TMUX_CALLS")
|
|
|
|
pane_args=$(tr '\0' '\n' < "$TMUX_CALLS")
|
|
|
|
echo "$pane_args" | grep -qxF "HOME=$PANE_TRUSTED_HOME" || \
|
|
|
|
echo "$pane_args" | grep -qxF "HOME=$PANE_TRUSTED_HOME" || \
|
|
|
@@ -392,6 +459,75 @@ echo "$interaction_policy_args" | grep -qF 'new-session' && \
|
|
|
|
echo "$output" | grep -qF 'operator interaction service requires runtime pi' || \
|
|
|
|
echo "$output" | grep -qF 'operator interaction service requires runtime pi' || \
|
|
|
|
fail "interaction pinned-policy check did not follow strict parsing"
|
|
|
|
fail "interaction pinned-policy check did not follow strict parsing"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #1241. The pane runs `mosaic yolo <runtime>` against PANE_PATH. A binary
|
|
|
|
|
|
|
|
# missing from that path is a launch failure, and it has to be named before the
|
|
|
|
|
|
|
|
# session is created — after it, the diagnostic dies with the pane.
|
|
|
|
|
|
|
|
assert_missing_pane_binary_rejected() {
|
|
|
|
|
|
|
|
local binary="$1"
|
|
|
|
|
|
|
|
local home="$ROOT/missing-$binary"
|
|
|
|
|
|
|
|
local agent="coder-missing-$binary"
|
|
|
|
|
|
|
|
write_generated "$home" "$agent"
|
|
|
|
|
|
|
|
rm -f "$home/.npm-global/bin/$binary"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
: > "$TMUX_CALLS"
|
|
|
|
|
|
|
|
local output
|
|
|
|
|
|
|
|
if output=$(MOSAIC_TEST_PANE_PID=$$ run_start "$home" "$agent" 2>&1); then
|
|
|
|
|
|
|
|
fail "launch succeeded with '$binary' absent from the pane PATH"
|
|
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
echo "$output" | grep -qF 'code=missing-binary' || fail "missing '$binary' diagnostic missing"
|
|
|
|
|
|
|
|
echo "$output" | grep -qF "'$binary'" || fail "missing-binary diagnostic did not name $binary"
|
|
|
|
|
|
|
|
if tr '\0' '\n' < "$TMUX_CALLS" | grep -qF new-session; then
|
|
|
|
|
|
|
|
fail "launcher created a session it knew would die ($binary absent)"
|
|
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assert_missing_pane_binary_rejected mosaic
|
|
|
|
|
|
|
|
assert_missing_pane_binary_rejected pi
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #1241. tmux destroys a session when its pane command exits, so no pane PID a
|
|
|
|
|
|
|
|
# second after new-session means the runtime died on startup. This used to be a
|
|
|
|
|
|
|
|
# WARNING about the heartbeat sidecar followed by exit 0 — three layers above it
|
|
|
|
|
|
|
|
# then reported a fleet that was not running.
|
|
|
|
|
|
|
|
: > "$TMUX_CALLS"
|
|
|
|
|
|
|
|
HOME_DEAD_PANE="$ROOT/dead-pane"
|
|
|
|
|
|
|
|
write_generated "$HOME_DEAD_PANE" "coder-dead-pane"
|
|
|
|
|
|
|
|
if output=$(MOSAIC_TEST_PANE_PID='' run_start "$HOME_DEAD_PANE" coder-dead-pane 2>&1); then
|
|
|
|
|
|
|
|
fail "launcher reported success over a pane that did not survive"
|
|
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
echo "$output" | grep -qF 'code=pane-did-not-survive' || fail "dead-pane diagnostic missing"
|
|
|
|
|
|
|
|
if echo "$output" | grep -qiF 'heartbeat'; then
|
|
|
|
|
|
|
|
fail "dead pane is still being reported as a heartbeat-sidecar problem"
|
|
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
tr '\0' '\n' < "$TMUX_CALLS" | grep -qF new-session || \
|
|
|
|
|
|
|
|
fail "dead-pane case did not reach the launch it is measuring"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #1241, the other way a pane fails. Above, tmux destroyed the session and
|
|
|
|
|
|
|
|
# has-session said so. Here the session is still there and no PID comes back
|
|
|
|
|
|
|
|
# after the retries — a different fault (the pane is alive but unusable, or
|
|
|
|
|
|
|
|
# tmux is answering inconsistently) that an operator has to be told apart from
|
|
|
|
|
|
|
|
# a runtime that died on startup.
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
# This case exists because the branch that handles it shipped with nothing able
|
|
|
|
|
|
|
|
# to reach it: the shim answered has-session only for the holder, so every
|
|
|
|
|
|
|
|
# non-holder agent landed in the session-is-gone branch no matter what. A
|
|
|
|
|
|
|
|
# defensive branch nothing exercises is the same shape as the bug this whole
|
|
|
|
|
|
|
|
# change is about, one layer down.
|
|
|
|
|
|
|
|
: > "$TMUX_CALLS"
|
|
|
|
|
|
|
|
HOME_NO_PID="$ROOT/pane-no-pid"
|
|
|
|
|
|
|
|
write_generated "$HOME_NO_PID" "coder-no-pid"
|
|
|
|
|
|
|
|
if output=$(MOSAIC_TEST_PANE_PID='' MOSAIC_TEST_HELD_SESSIONS='=coder-no-pid:0.0' \
|
|
|
|
|
|
|
|
run_start "$HOME_NO_PID" coder-no-pid 2>&1); then
|
|
|
|
|
|
|
|
fail "launcher reported success over a session with no resolvable pane PID"
|
|
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
echo "$output" | grep -qF 'code=pane-pid-unresolved' || \
|
|
|
|
|
|
|
|
fail "session-present/no-PID was not reported as pane-pid-unresolved: $output"
|
|
|
|
|
|
|
|
if echo "$output" | grep -qF 'code=pane-did-not-survive'; then
|
|
|
|
|
|
|
|
fail "a session tmux still reports was diagnosed as a destroyed session"
|
|
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
if echo "$output" | grep -qiF 'heartbeat'; then
|
|
|
|
|
|
|
|
fail "an unresolvable pane PID is still being reported as a heartbeat-sidecar problem"
|
|
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Exact stop derives the socket exclusively from the validated generated
|
|
|
|
# Exact stop derives the socket exclusively from the validated generated
|
|
|
|
# projection and ignores an ambient socket supplied by the caller.
|
|
|
|
# projection and ignores an ambient socket supplied by the caller.
|
|
|
|
: > "$TMUX_CALLS"
|
|
|
|
: > "$TMUX_CALLS"
|
|
|
|