Skip to content

tests: freshEnv() omits git identity, so stub ref writes stall where the hostname does not resolve (21 failures, ~880s) #11

Description

@jdoit18950

Summary

freshEnv() in tests/harness.mjs sets GIT_CONFIG_GLOBAL=/dev/null and
GIT_CONFIG_SYSTEM=/dev/null but does not supply a git identity. Any git invocation
that writes a ref therefore has no reachable user.email, so git falls back to
synthesizing user@host — which calls getaddrinfo() on the machine's hostname.

On a host where the hostname does not resolve promptly, that call blocks. The stub
herdr worktree create runs a real git worktree add, whose internal
git branch --quiet then hangs until runPane's 30s spawnSync timeout fires.

Result on such a host: 21 failures out of 237, all in fanout.test.mjs, and the
suite takes ~880s. With an identity supplied it is 237/237 in ~75s.

The harness already knows about this hazard — tests/harness.mjs:17 says "harness env
has GIT_CONFIG_GLOBAL=/dev/null, so identity must ride in"
— and the module-scope
gitIdent correctly rides in the harness's own git() helper. The gap is that
freshEnv(), which is what the stub inherits, never got the same treatment.

Environment

  • herdr-swarm main (v0.3.0)
  • Linux, git 2.43.0, Node 24
  • Host hostname absent from /etc/hosts; nsswitch hosts: files mdns4_minimal [NOTFOUND=return] dns

Reproduce

Simulate the resolver stall (or run on any host where getent hosts $(hostname) is slow
or times out), then:

node --test tests/fanout.test.mjs

Every test that reaches fan-out fails with status: null at exactly 30000ms.

Minimal proof the identity — not the plugin — is the variable:

git init -q r && cd r && git -c user.email=t@t -c user.name=t commit -q --allow-empty -m base

# hangs (exit 124)
timeout 10 env GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=/dev/null \
  git branch b1 HEAD

# 0.003s, exit 0
timeout 10 env GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=/dev/null \
  GIT_AUTHOR_NAME=t GIT_AUTHOR_EMAIL=t@t \
  GIT_COMMITTER_NAME=t GIT_COMMITTER_EMAIL=t@t \
  git branch b2 HEAD

Diagnosis trail

The failure reads exactly like a plugin hang or a herdr-version incompatibility, which
is what makes it worth guarding against. What identifies it:

$ cat /proc/<pid>/wchan
poll_schedule_timeout.constprop.0

$ ls -l /proc/<pid>/fd
3 -> .../.git/logs/refs/heads/<branch>     # the reflog being written
4 -> socket:[...]                          # a socket, during a purely local ref write

$ strace -e trace=network ...
connect(4, {AF_UNIX, "/var/run/nscd/socket"}) = -1 ENOENT   x4
socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 4                 # UDP DNS query, unanswered

A socket opened during a local git branch is the tell.

Suggested fix

Add the identity to freshEnv() alongside the config-nulling it already does:

GIT_CONFIG_GLOBAL: "/dev/null",
GIT_CONFIG_SYSTEM: "/dev/null",
GIT_AUTHOR_NAME: "hs-test", GIT_AUTHOR_EMAIL: "hs-test@example.invalid",
GIT_COMMITTER_NAME: "hs-test", GIT_COMMITTER_EMAIL: "hs-test@example.invalid",

Reusing the exported gitIdent object would keep it DRY. This is a one-line-ish change
that also cut the suite from ~880s to ~75s here, so it may be worth it on CI runners
regardless of whether they exhibit the stall.

Happy to open a PR if useful.


Context: found while evaluating the plugin for adoption. Once the identity was supplied
the suite was fully green, so this is purely a harness portability issue — no defect in
the plugin itself.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions