Run the tests under the race detector with make test-race (closes #18)
check / check (push) Failing after 2s
check / check (push) Failing after 2s
script/test-race runs go test -race in a digest-pinned Debian golang image that has gcc, since the detector needs cgo and the build keeps it off. The checkout is mounted read-only and the container is removed afterwards. The tests run as the calling user, or as nobody when that is root, so the tests that make a file unreadable still see the read fail. It is not part of make check. The detector found no races. Model: opus-5-5
This commit is contained in:
@@ -6,7 +6,7 @@ BINARY := sfdupes
|
|||||||
VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo dev)
|
VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo dev)
|
||||||
LDFLAGS := -X main.Version=$(VERSION)
|
LDFLAGS := -X main.Version=$(VERSION)
|
||||||
|
|
||||||
.PHONY: sfdupes build bootstrap setup test lint fmt fmt-check check docker hooks clean
|
.PHONY: sfdupes build bootstrap setup test test-race lint fmt fmt-check check docker hooks clean
|
||||||
|
|
||||||
# Standard targets are thin shims; the implementations live in script/
|
# Standard targets are thin shims; the implementations live in script/
|
||||||
# per the scripts-to-rule-them-all pattern.
|
# per the scripts-to-rule-them-all pattern.
|
||||||
@@ -27,6 +27,9 @@ setup:
|
|||||||
test:
|
test:
|
||||||
@script/test
|
@script/test
|
||||||
|
|
||||||
|
test-race:
|
||||||
|
@script/test-race
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
@script/lint
|
@script/lint
|
||||||
|
|
||||||
|
|||||||
@@ -742,14 +742,23 @@ entrypoints are:
|
|||||||
installed: they run in Docker (see `script/lint` and `script/fmt`) and never
|
installed: they run in Docker (see `script/lint` and `script/fmt`) and never
|
||||||
from a host install, so there is no host copy to drift from the pin. A missing
|
from a host install, so there is no host copy to drift from the pin. A missing
|
||||||
`docker` is warned about rather than installed or treated as fatal —
|
`docker` is warned about rather than installed or treated as fatal —
|
||||||
everything except linting and formatting works without it. Ends with
|
everything except linting, formatting and `make test-race` works without it.
|
||||||
`go mod download`.
|
Ends with `go mod download`.
|
||||||
- `script/setup` — make a fresh clone ready for development: runs
|
- `script/setup` — make a fresh clone ready for development: runs
|
||||||
`script/bootstrap`, then `script/install-precommit`.
|
`script/bootstrap`, then `script/install-precommit`.
|
||||||
- `script/projectname` — print this project's name (`sfdupes`). Scripts that
|
- `script/projectname` — print this project's name (`sfdupes`). Scripts that
|
||||||
need the name call it, so they stay identical across repositories.
|
need the name call it, so they stay identical across repositories.
|
||||||
- `script/test` — run the test suite with a 30-second timeout and coverage
|
- `script/test` — run the test suite with a 30-second timeout and coverage
|
||||||
enabled, rerunning verbosely on failure so the logs show which test failed.
|
enabled, rerunning verbosely on failure so the logs show which test failed.
|
||||||
|
- `script/test-race` — run the test suite under the race detector with a
|
||||||
|
60-second timeout. The detector needs cgo and a C compiler, which the build
|
||||||
|
never uses, so the tests run in a digest-pinned Debian `golang` image that has
|
||||||
|
`gcc`, with the checkout mounted read-only; the container is removed when it
|
||||||
|
exits. They run as the calling user, or as `nobody` when that is root, because
|
||||||
|
several tests make a file unreadable and root reads it anyway; only then must
|
||||||
|
the checkout be readable by other users. Not part of `script/check`. Every run
|
||||||
|
starts with empty caches, so it needs the network and takes minutes, and the
|
||||||
|
mount needs a local docker daemon.
|
||||||
- `script/lint` — run the linter. It builds `Dockerfile.lint`, which copies the
|
- `script/lint` — run the linter. It builds `Dockerfile.lint`, which copies the
|
||||||
repository into the digest-pinned `golangci/golangci-lint` image and runs
|
repository into the digest-pinned `golangci/golangci-lint` image and runs
|
||||||
`golangci-lint config verify` and `golangci-lint run` as build steps, so a
|
`golangci-lint config verify` and `golangci-lint run` as build steps, so a
|
||||||
@@ -840,6 +849,8 @@ compile recipe:
|
|||||||
- `make setup` — prepare a fresh clone: `bootstrap` plus the pre-commit hook.
|
- `make setup` — prepare a fresh clone: `bootstrap` plus the pre-commit hook.
|
||||||
- `make test` — run the test suite (30-second timeout; reruns with `-v` on
|
- `make test` — run the test suite (30-second timeout; reruns with `-v` on
|
||||||
failure).
|
failure).
|
||||||
|
- `make test-race` — run the test suite under the race detector, in Docker (see
|
||||||
|
`script/test-race`); requires `docker`. Not part of `make check`.
|
||||||
- `make lint` — run `golangci-lint` with the repo config, in Docker (see
|
- `make lint` — run `golangci-lint` with the repo config, in Docker (see
|
||||||
`script/lint`); requires `docker`.
|
`script/lint`); requires `docker`.
|
||||||
- `make fmt` / `make fmt-check` — format the Go sources and the Markdown /
|
- `make fmt` / `make fmt-check` — format the Go sources and the Markdown /
|
||||||
|
|||||||
@@ -28,6 +28,10 @@
|
|||||||
|
|
||||||
# Completed Steps
|
# Completed Steps
|
||||||
|
|
||||||
|
- `make test-race` runs the test suite under the race detector in a cgo-enabled
|
||||||
|
container, outside `make check` (2026-10-04,
|
||||||
|
https://git.eeqj.de/sneak/sfdupes/issues/18)
|
||||||
|
|
||||||
- a bare `docker build .` fails with a message naming `script/cibuild` and
|
- a bare `docker build .` fails with a message naming `script/cibuild` and
|
||||||
`script/docker` instead of serving the gates from cache (2026-10-04,
|
`script/docker` instead of serving the gates from cache (2026-10-04,
|
||||||
https://git.eeqj.de/sneak/sfdupes/issues/39)
|
https://git.eeqj.de/sneak/sfdupes/issues/39)
|
||||||
@@ -497,5 +501,6 @@ Accepted divergences (no action):
|
|||||||
|
|
||||||
- flat single-package layout with `.go` files in the repo root — fine for a
|
- flat single-package layout with `.go` files in the repo root — fine for a
|
||||||
small single-binary tool per the Go styleguide; the tracker audit agrees
|
small single-binary tool per the Go styleguide; the tracker audit agrees
|
||||||
- `go test` runs without `-race` — the repo mandates `CGO_ENABLED=0` (pure-Go
|
- `make test` runs without `-race` — the repo mandates `CGO_ENABLED=0` (pure-Go
|
||||||
builds) and the race detector requires cgo
|
builds) and the race detector requires cgo, so the detector runs in a separate
|
||||||
|
cgo-enabled container, `make test-race`, which is not part of `make check`
|
||||||
|
|||||||
+8
-7
@@ -7,8 +7,8 @@
|
|||||||
# installed: golangci-lint (script/lint) and prettier (script/fmt,
|
# installed: golangci-lint (script/lint) and prettier (script/fmt,
|
||||||
# script/fmt-check) run via docker only, pinned by hash, so their only
|
# script/fmt-check) run via docker only, pinned by hash, so their only
|
||||||
# prerequisite is a working docker — which is warned about, not
|
# prerequisite is a working docker — which is warned about, not
|
||||||
# installed, because everything except linting and formatting works
|
# installed, because everything except linting, formatting and
|
||||||
# without it.
|
# make test-race works without it.
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
||||||
@@ -75,13 +75,14 @@ main() {
|
|||||||
|
|
||||||
# Linting and Markdown formatting run via docker only, so docker is
|
# Linting and Markdown formatting run via docker only, so docker is
|
||||||
# their prerequisite rather than something bootstrap installs. Warn,
|
# their prerequisite rather than something bootstrap installs. Warn,
|
||||||
# do not fail: everything except `make lint`, `make fmt` and
|
# do not fail: everything except `make lint`, `make fmt`,
|
||||||
# `make fmt-check` — and, through them, `make check`, `make docker`
|
# `make fmt-check` and `make test-race` — and, through them,
|
||||||
# and the pre-commit hook — works without it.
|
# `make check`, `make docker` and the pre-commit hook — works
|
||||||
|
# without it.
|
||||||
if missing docker; then
|
if missing docker; then
|
||||||
echo "bootstrap: WARNING: docker not found; make lint, make fmt," >&2
|
echo "bootstrap: WARNING: docker not found; make lint, make fmt," >&2
|
||||||
echo "bootstrap: make fmt-check, make check and make docker" >&2
|
echo "bootstrap: make fmt-check, make check, make docker and" >&2
|
||||||
echo "bootstrap: require it." >&2
|
echo "bootstrap: make test-race require it." >&2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
go mod download
|
go mod download
|
||||||
|
|||||||
Executable
+40
@@ -0,0 +1,40 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# script/test-race: run the test suite under the race detector. Not part
|
||||||
|
# of script/check.
|
||||||
|
#
|
||||||
|
# The race detector needs cgo and a C compiler, which the host build
|
||||||
|
# never uses, so the tests run in a golang image that has gcc. The
|
||||||
|
# checkout is mounted read-only, so the docker daemon must be local. The
|
||||||
|
# container starts with empty caches every time: each run downloads the
|
||||||
|
# dependencies and compiles them with the detector, which needs the
|
||||||
|
# network and takes minutes.
|
||||||
|
#
|
||||||
|
# The tests run as the calling user, never as root: several of them make
|
||||||
|
# a file unreadable and expect reading it to fail, and root reads it
|
||||||
|
# anyway. When the caller is root they run as nobody, and then the
|
||||||
|
# checkout must be readable by other users. Neither user has a home
|
||||||
|
# directory in the image, so HOME is /tmp, where Go puts its build cache.
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
||||||
|
|
||||||
|
# golang:1.25-trixie, 2026-10-04. Debian rather than the Alpine image the
|
||||||
|
# Dockerfile builds with, because this one includes gcc.
|
||||||
|
IMAGE="golang@sha256:2c4c60ef415fbfa5e90300722293bef36c5e63fae17570ce18f580af933dbd73"
|
||||||
|
|
||||||
|
main() {
|
||||||
|
user="$(id -u):$(id -g)"
|
||||||
|
if [ "$(id -u)" -eq 0 ]; then
|
||||||
|
user=65534:65534
|
||||||
|
fi
|
||||||
|
docker run --rm \
|
||||||
|
--user "$user" \
|
||||||
|
--env HOME=/tmp \
|
||||||
|
--env CGO_ENABLED=1 \
|
||||||
|
--volume "$ROOT:/src:ro" \
|
||||||
|
--workdir /src \
|
||||||
|
"$IMAGE" \
|
||||||
|
go test -race -timeout 60s ./...
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
Reference in New Issue
Block a user