smoke: workspace export scenario + smoke-fresh target + fix the export bug it caught

The export round-trip (`vm create` → `workspace prepare` → guest edit →
`workspace export`) exposed a reproducible failure on Debian bookworm
guests: `git read-tree HEAD --index-output=/tmp/...` returns exit 128
"unable to write new index file" when the target lives on tmpfs while
`.git` is on the workspace overlay. Move the temp index into
`$(git rev-parse --git-dir)` so it shares a filesystem with `.git/index`
and the lockfile + rename + hardlink dance git does internally works.

Alongside:
- new workspace-export smoke scenario that would have caught this at
  the boundary between daemon and guest git
- `make smoke-fresh` = `smoke-clean && smoke` for release-time runs
  that want first-install paths (migrations, image pull) stamped into
  the coverage report

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Thales Maciel 2026-04-23 11:34:55 -03:00
parent 672d7151e9
commit e94e7c4dcc
No known key found for this signature in database
GPG key ID: 33112E6833C34679
3 changed files with 55 additions and 2 deletions

View file

@ -141,6 +141,39 @@ grep -q 'untracked-marker' <<<"$inc_out" || die "--include-untracked didn't ship
# Restore repo to tracked-only state for any later scenarios.
rm -f "$repodir/smoke-untracked.txt"
# --- workspace export round-trip --------------------------------------
# Exercises ExportVMWorkspace: create a VM, prepare the workspace,
# write a new file inside the guest, then export and assert the
# emitted patch sees the guest-side change. If the export pipeline
# (temp-index, git add -A, diff --binary) ever stops capturing
# guest-side changes, this scenario catches it.
log 'workspace export: create + prepare + guest edit + export + assert marker'
export_vm='smoke-export'
cleanup_export_vm() {
"$BANGER" vm delete "$export_vm" >/dev/null 2>&1 || true
}
# Chain the VM cleanup with the existing runtime_dir trap so a mid-
# scenario failure still tears the VM down before the script exits.
# shellcheck disable=SC2064
trap "cleanup_export_vm; rm -rf '$runtime_dir'" EXIT
"$BANGER" vm create --name "$export_vm" --image debian-bookworm >/dev/null \
|| die "export: vm create exit $?"
"$BANGER" vm workspace prepare "$export_vm" "$repodir" >/dev/null \
|| die "export: workspace prepare exit $?"
"$BANGER" vm ssh "$export_vm" -- sh -c 'echo guest-edit > /root/repo/new-guest-file.txt' \
|| die "export: guest-side file write exit $?"
export_patch="$runtime_dir/smoke-export.diff"
"$BANGER" vm workspace export "$export_vm" --output "$export_patch" \
|| die "export: workspace export exit $?"
[[ -s "$export_patch" ]] || die "export: patch file empty at $export_patch"
grep -q 'new-guest-file.txt' "$export_patch" \
|| die "export: patch missing new-guest-file.txt marker (head: $(head -c 400 "$export_patch"))"
cleanup_export_vm
# shellcheck disable=SC2064
trap "rm -rf '$runtime_dir'" EXIT
# --- concurrent vm runs -----------------------------------------------
# Stresses per-VM lock scoping, the tap pool warm-up path, and
# createVMMu's narrow reservation window. Two `vm run --rm` invocations