test: exercise binary self-replacement on Windows in CI - #58
Merged
Conversation
The windows-latest CI leg added in 0.8.0 only ran go build and go test; it never exercised a binary replacing itself, which is the one part of grant update whose semantics genuinely differ on Windows (a running executable cannot be deleted, only renamed). Add selfupdate_e2e-tagged end-to-end tests that compile two real fixture binaries from a dependency-free module, execute one, and replace it through grant's own applyBinaryTo/applyWithOptions while a process is still running from that image. Cover the success path and the rollback path, and assert the rolled-back binary still executes. No network access is needed, so this does not depend on GitHub releases. Run the step on both ubuntu-latest and windows-latest so the platforms are directly comparable. No production code changed: applyWithOptions and the commitFn seam already existed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The
windows-latestCI leg added in #54 runsgo buildandgo test, but never exercises the one thing that actually differs on Windows: a binary replacing itself. A running executable there cannot be deleted, only renamed — which is precisely whyminio/selfupdateswaps with two renames instead of writing over the target. Nothing in CI proved that path worked.What this adds
internal/selfupdate/e2e_test.go, behind theselfupdate_e2ebuild tag:-ldflags -X main.version=VARIANT-A/B). No network access — this does not touch GitHub releases.applyBinaryTo/applyWithOptionswhile a process is still running from that image.Each test is table-driven over
hold=false/hold=trueso the locked and unlocked cases are directly comparable.Making the lock real
A test that claims to exercise file locking but silently doesn’t is worse than no test. The target is held by a live child process (
fixture hold, blocking on stdin) rather than a mere open handle, because a mapped executable image is what Windows refuses to delete.heldProcess.alive()asserts the child is still running both immediately before and after the swap, so ahold=truecase can never quietly degrade into thehold=falsecase.One honest platform difference, asserted rather than hidden
minio.CommitBinarycannotos.Removethe.grant.oldbackup while a process still runs from that image, so it marks the file hidden (SetFileAttributesW) and leaves it. So on Windows,.grant.olddoes survive an update performed against a running binary. That is by design, and it does not accumulate — the nextCommitBinaryremoves the old path before renaming.Rather than relax the assertion to make the suite green, the test encodes the real contract:
.grant.newmust never survive, on either platform..grant.oldmust not survive on POSIX, or on Windows when nothing is running.CI
The step runs on both
ubuntu-latestandwindows-latest, deliberately with noif:guard — comparing the platforms is the entire point.No production changes
applyWithOptionsand thecommitFnseam already existed.internal/selfupdate/*.gois untouched; no test seam had to be added or widened.Verified locally
make build,make test,make lint, andgo test -tags=selfupdate_e2e -race ./internal/selfupdate/all pass on Linux.golangci-lint run --build-tags=selfupdate_e2eis clean. The Windows leg could not be run locally — that is what this PR’s CI run is for.