Skip to content

Add a bats (or mocked-curl) test covering the offline-reclaim and online-refuse branches #159

Open

Description

@github-actions

What

Add an automated test that exercises the two branches of reclaim_orphaned_name() in entrypoint.sh:

  1. Offline-reclaim branch — a same-named runner is listed with status == "offline", so the function issues a DELETE and returns success.
  2. Online-refuse branch — a same-named runner is listed with a non-offline status, so the function does not delete and the entrypoint refuses to start (preserving the deliberate no---replace stance).

The test must not require a live GitHub repo or network access.

Why

The reclaim logic is the core of PR #154 and its two decision branches are exactly the kind of behaviour that silently regresses: a future refactor of the jq extraction, the [[ -n "${id}" ]] guard, or the status comparison could flip the online-refuse branch into a delete and nobody would notice until a live runner was clobbered. The manual reproduce steps in the original issue (hard-kill, restart, observe crashloop) require a live repo and a rate-limited host, so they are not a regression guard. A bats test (or a shell test with a mocked curl) pins both branches down cheaply.

How

  • Add a bats test file (e.g. test/entrypoint.bats) or, if bats is not acceptable as a dev dependency, a plain shell test that sources entrypoint.sh with a mocked curl on PATH.
  • Mock curl so that:
    • The listing call (GET /actions/runners) returns a JSON body containing a single runner with the same RUNNER_NAME and a controllable status.
    • The DELETE call records that it was invoked (e.g. writes to a temp file) and returns a success status.
  • Case 1 (offline): assert the mock DELETE was invoked exactly once and the function returned success.
  • Case 2 (online): assert the mock DELETE was not invoked and the entrypoint exits non-zero / refuses to start.
  • Keep the mock minimal — only the endpoints reclaim_orphaned_name() actually calls need to be stubbed. Do not attempt to mock the full registration flow.
  • If bats is used, add a short note to the repo's test docs (or the PR description) on how to run it locally.

Files Affected

  • entrypoint.sh (source under test; no changes required unless a seam is needed to make it sourceable)
  • test/entrypoint.bats (new — or an equivalent shell test path if bats is not adopted)
  • Unknown (test runner config / CI workflow, if one exists and needs to invoke the new test)

Constraints

  • Must not require network access, a live GitHub repo, or a real PAT.
  • Must not change the runtime behaviour of entrypoint.sh; this is test-only. If a small refactor is needed to make the function sourceable/testable, it must be behaviour-preserving.
  • Out of scope: the other follow-ups from the same review (the unconditional rm -f .runner, the command -v jq guard, the single-pass jq extraction, Retry-After handling). Those are separate issues.
  • Out of scope: testing the jq-missing silent no-op path — that is covered by the separate jq guard follow-up.

LLM tier

Sonnet — new test coverage requiring design decisions (how to mock curl, how to make the entrypoint sourceable, what to assert), but no architectural ambiguity.

Success looks like

  • A test exists that fails if the offline branch stops issuing the DELETE.
  • A test exists that fails if the online branch starts issuing a DELETE (or stops refusing to start).
  • Both tests pass on the current entrypoint.sh from PR Reclaim our own offline registration instead of crashlooping on it #154.
  • The tests run without network access and without a GitHub token.
  • Running the test suite is documented (command + any prerequisites).

Failure looks like

  • Tests that only assert the function "ran" without checking whether DELETE was called — they would pass on both branches and guard nothing.
  • Tests that require a live repo, a real token, or network access.
  • A refactor of entrypoint.sh that changes runtime behaviour in order to make it testable.
  • The online-refuse case being tested only by asserting a non-zero exit, without asserting that no DELETE was issued.

Follow-up from AI review of PR #154.

Activity

  1. added
    ai-suggestedSuggested by AI code review
    sonnetSuitable for Claude Sonnet (moderate reasoning)
    on Sep 19, 2026
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

    ai-suggestedSuggested by AI code reviewsonnetSuitable for Claude Sonnet (moderate reasoning)

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions