Three review follow-ups that the last release review asked for: - TESTING.md no longer claims a formulation vet accepts for the Windows mapped slice conversion; measured on go1.26.8/windows-amd64, the unsafe.Slice call, a typed pointer in a variable and an array cast are all flagged, and the one accepted shape is the deprecated reflect.SliceHeader field assignment, which trades a false positive for a less safe conversion. - The report chapter drops the byte-identity claim about rows written without full_path and signature_cache_hit and states what the fields are instead. - The mmap divergence note and File's own comment now say that ReadAt past the end reports an invalid offset rather than io.EOF, and that a caller keeping the descriptor must keep the reader reachable because the finalizer owns it. - TestManagedSignatureIsNotOrdinaryCopiedXattr now exercises the copy path: a decoy managed entry on the source and an ordinary control attribute prove the metadata restore ran, the target carries no managed attribute, and the source keeps its own entry.
12 KiB
Testing
Run all commands from the repository root.
Prerequisites
- Go 1.26.8 or newer:
go.moddeclaresgo 1.26.8, and the code usescontext.WithoutCancelanderrors.Join. - Enough free space under the system temporary directory for test files and compiled binaries.
- A host file system that supports the operations exercised by the selected tests.
- A host file system that supports the managed signature xattr for the cache tests. A test that cannot store it skips itself with a diagnostic.
When this module is checked out inside another Go workspace, run every command with an
explicit empty GOFLAGS and GOWORK=off so the parent build flags and workspace do not
leak into module resolution:
GOFLAGS= GOWORK=off go test ./...
Standard checks
Run every local gate with the single command that owns them:
make check
It runs go test ./..., go vet ./..., the four cross-builds
(linux/amd64, windows/amd64, darwin/arm64, freebsd/amd64) and a gofmt check, and fails on
the first gate that fails. The individual commands below are the fallback for running one gate
on its own; apply the GOFLAGS= GOWORK=off prefix from above to them as well when this module
is checked out inside another Go workspace.
Run the complete test suite:
go test ./...
Run static analysis:
go vet ./...
Run the suite with the race detector (not part of make check):
go test -race ./...
End-to-end tests
The command end-to-end test builds the acp command, copies a directory tree through the CLI, and verifies:
- regular and empty file contents;
- nested destination paths;
- successful job status and destinations;
- JSON report decoding;
- SHA256 generation for every copied file.
Run only the command test with:
go test -run '^TestACPCommandE2E$' -v .
The library end-to-end test uses the af05f05c shell and the push engine directly, with two
destinations, and verifies:
- the shell's wildcard enumeration and the complete prepare, copy, cleanup, and event pipeline;
- regular, empty, and nested file contents at both destinations;
- exactly one result per submitted item, with the submitted instance in
Result.Joband one target outcome per destination; - successful report status and destination sets;
- file size and exact SHA256 values.
Run only the library test with:
go test -run '^TestACPLibraryE2E$' -v .
Run both end-to-end tests with:
go test -run '^TestACP(Command|Library)E2E$' -v .
Run every command end-to-end test, including the interrupt and exit-status cases, with:
go test -run '^TestACPCommand' -v .
The interrupt test sends SIGINT in the middle of a run and requires every selected file to
appear exactly once in the report; because the stop abandons work, the command must exit
non-zero. TestACPCommandExitsNonZeroWhenACopyFails refuses one target with -n and requires
a non-zero exit status together with a report that names the refused target.
The command end-to-end tests are skipped when go test is run with -short.
Focused tests
Run cache concurrency tests:
go test -race -run '^TestCache' -count=20 .
Run path and mountpoint tests, which resolve real paths to their mount point and pin the failure a path that cannot be made absolute reports:
go test -run '^(TestComparePath|TestSourceRoot|TestFS|TestGetMountpointReportsAbsFailure|TestFindMountpoint)$' .
Run option and event tests, which pin the last-wins option rule, the validation of every option, and the single-goroutine event handler contract:
go test -run '^(TestWithEventHandlerIsLastWins|TestNewDoesNotWriteIntoTheCallersOptionSlice|TestRunCallsOneEventGoroutineAtATime|TestNewStreamRejectsInvalidOptions|TestNewStreamRejectsNilResultsCallback|TestNewStreamRejectsJobOptions|TestNewRejectsInvalidOptions|TestNewRejectsNegativeDeviceThreads)$' .
Run report tests, which pin the JSON contract with the standard library, the nil handling of report errors, the indented writer, and the terminal row of a failed item:
go test -run '^(TestErrorJSONMarshal|TestJobFailTargetsJSON|TestReportStandardLibraryRoundTrip|TestReportToJSONStringIndentUsesSpaces|TestRunReportsAFailedItemAsATerminalRow)$' .
Run the command's report and exit-status tests, which pin the report shape, the failure decision, the stored report file, and the exact-target branch:
go test -run '^(TestReportKeepsFailuresInsideTheFileRow|TestReportAccountsForEveryEntryAfterAGracefulStop|TestReportFailureDecision|TestStoreReportWritesTheFailureDocument|TestAccurateTargetUsesItsTargets)$' ./cmd/acp
Run disk usage tests, which pin the target error identities and the reservation accounting across a refresh:
go test -run '^(TestMappingErrorIdentities|TestDiskUsageRefreshKeepsInflightReservations|TestDiskUsageAccountsLandedBytes)$' .
Run the fatal-panic safety net tests, which pin that a panicking worker becomes the run error and that a panicking hash consumer still releases the cache gate the target writers wait on:
go test -run '^(TestWrapRecordsAFatalPanic|TestRunReleasesTheCacheGateWhenTheHashPanics)$' .
Run the shell's file selection and enumeration tests, which pin the relative-path mapping, the platform path order, and the fast failure on a repeated relative path:
go test -run '^(TestWalkWildcardMapsSourcesOntoTargets|TestWalkWildcardMapsASingleFileOntoTargets|TestShellRejectsRepeatedRelativePaths|TestNewRejectsInvalidInput|TestSourceRoot)$' .
Run item contract tests, which pin one result per accepted item, one outcome per requested target in request order, a multi-chunk copy to every target, failure routing, single-goroutine callback delivery, and the report row of a failed item:
go test -run '^(TestRunReportsEveryAcceptedItemExactlyOnce|TestRunKeepsLinearOrderingPastAnUnprocessedItem|TestRunReportsUnprocessableItemsAsFailures|TestRunReportsOneOutcomePerRequestedTargetInOrder|TestRunCopiesAChunkedSourceToEveryTarget|TestRunReportsTargetFailureAsItemOutcome|TestRunDeliversResultsFromOneGoroutine|TestRunReportsAFailedItemAsATerminalRow|TestPrepareReportsUnstartedItemsWithoutReadingThem|TestPrepareReadsNoContentWhenThePolicyNeedsNone|TestWriteKeepsTargetOutcomesWhenTheReadAlsoFails|TestWriteReportsTheFactsItReadWhenTheSourceChanged|TestRunRejectsReuseOnlyPolicyForItemsWithTargets|TestRunKeepsEveryOtherPolicyForItemsWithTargets|TestRunReturnsErrorWhenTheResultsCallbackPanics|TestRunReturnsErrorWhenAnEventHandlerPanics|TestWriteReportsTargetlessReadFailureAsItemFailure)$' .
Run the reshape's new contract tests, which pin the result queue and the result batch as separate
options, the immediate delivery of a result that carries an error, the freshness of a delivered
batch, the cancellation semantics of a results callback error, the feed's backpressure and
refusal, the one EventFinished per registration, the hard-stop escape of every handoff, the
exhausted-target path, the shell's exact-target run, and the fatal-panic boundary:
go test -run '^(TestFailedResultBypassesTheResultBuffer|TestSuccessResultsAreBatchedAndFlushedOnClose|TestDeliveredBatchesAreFreshSlices|TestEventHandlerSeesExactlyOneFinishedEvent|TestResultsCallbackErrorActsAsACancellation|TestSubmitBlocksWhileTheReadBufferIsFull|TestSubmitRejectsANilItem|TestStreamReportsSubmissionFailureAsRunError|TestStreamCopyReleasesAChunkHandoffAfterHardStop|TestSubmitDropsAnEventAfterHardStop|TestFailAllReportsEveryTargetAsFailed|TestShellCopiesAnAccurateJob|TestWrapStopsAPanickingPipeline)$' .
Run graceful-stop tests, which drive a feed that spans several batches and cancel the context mid-run:
go test -run '^(TestRunStopsFeedingItemsAfterGracefulStop|TestRunDoesNotReportAStopAfterACompleteRun|TestRunCancellationDrainsPrefetchedItems|TestRunReportsEveryAcceptedItemExactlyOnce)$' .
Run linear stream-order tests:
go test -run '^(TestRunCopiesItemsToLinearTarget|TestForwardPreparedOrdersOnlyLinearTargets|TestRunAppliesBoundedBackpressure|TestLinearTargetStopsWhenDiskUsageEstimateIsInsufficient|TestStoppedLinearTargetRefusesSubmission)$' .
Run the target-failure drain test, which proves every read buffer is released and no goroutine deadlocks. It uses its own failing writer, so it runs on every platform:
go test -race -run '^TestWriteFailureDrainsBuffersAndTargets$' .
On Linux, run the whole Linux-only file: it pins an ENOSPC write failure and its mapping onto
ErrTargetNoSpace, a refusing device that drains its queued buffers, and the pre-allocation
failure of a filled volume (that one mounts a small tmpfs and skips when the host refuses).
go test -race -run '^(TestRunMapsDeviceFullToTargetNoSpace|TestDeviceFullWriteFailureDrainsQueuedBuffers|TestFullVolumePreallocationReportsNoSpace)$' .
These three select no test on another platform: the file that defines them is Linux-only. Note
that /dev/full refuses fallocate with ENODEV, which is none of the errors a target operation
classifies (ENOSPC, EROFS, EIO): the non-linear pre-allocation there fails that target with
the device's own ENODEV, not with ErrTargetIO and not with ErrTargetNoSpace. The
ErrTargetNoSpace identity for that path comes from the filled-volume test, which produces a real
ENOSPC.
Run hash policy tests, which pin the reuse, read, and refresh matrix, and the no-op policy of a file system without the managed signature attribute:
go test -run '^(TestRunHashPolicyMatrix|TestRunRefreshWritesOnlyWhenStoredHashDiffers|TestRunTransferAlwaysReadsAndRefreshesTargets|TestOverwriteInvalidatesSignatureWithoutCache|TestRunCorruptSignatureIsWarning|TestRunSignatureCacheZeroLength|TestRunIgnoresUnsupportedSignatureXattr)$' .
Run every signature cache test, including the codec, the descriptor identity tests that prove a cache entry never travels through a reopened path, and the publication-order test that proves an item publishes its entry before its result:
go test -run '^(TestCachedSignatureCodec|TestSignatureCache|TestRunSignature|TestRunHashPolicy|TestRunRefresh|TestRunTransfer|TestOverwriteInvalidates|TestRunCorruptSignature|TestRunReadsTheStoredHash|TestRunWrites|TestRunPublishes|TestRunHoldsTargetCache|TestManagedSignature)' .
Run acp-rewrite tests, which pin one rewrite through its scratch file, the state and report
round trips, the interrupted-run cleanup, and the dry-run and resume command runs:
go test ./cmd/acp-rewrite
go test -run '^(TestRewriteFileCommitsTheFinalPath|TestRewriteFileRejectsAMissingSource|TestStateRoundTrip|TestReportRoundTripKeepsHistory|TestCleanupTmpFilesRemovesOnlyScratchFiles|TestRewriteCommandResumesAfterDryRun)$' -v ./cmd/acp-rewrite
Run the memory-mapping contract tests, which pin the reader, slice, close and descriptor ownership contracts:
go test -v ./mmap
Cross-platform checks
Build all packages for Linux and Windows:
GOOS=linux GOARCH=amd64 go build ./...
GOOS=windows GOARCH=amd64 go build ./...
The Darwin and FreeBSD builds cover the platform-specific memory mapping and the managed
signature attribute; mmap_other.go is the FreeBSD fallback, so only the FreeBSD build compiles
it:
GOOS=darwin GOARCH=arm64 go build ./...
GOOS=freebsd GOARCH=amd64 go build ./...
Compile the Windows-specific root package tests without running them:
GOOS=windows GOARCH=amd64 go test -c -o /tmp/acp-windows.test .
make check builds for Windows but vets only the host platform. GOOS=windows GOARCH=amd64 go vet ./... reports the conversion that turns the address syscall.MapViewOfFile returned into the
mapped slice, and it flags that conversion in every formulation this package would use: the
unsafe.Slice call in mmap/mmap_windows.go, a typed pointer kept in a variable, an array cast,
and a reflect.SliceHeader literal, which gets its own possible misuse of reflect.SliceHeader
message. The one shape vet accepts is the deprecated (*reflect.SliceHeader)(unsafe.Pointer(&data))
field assignment, which trades a false positive for a less safe conversion, so the diagnostic is
accepted rather than worked around.
Change checklist
Before submitting a change:
- Run
make check, the single command for the local gates:gofmt,go test ./...,go vet ./...and the four cross-builds. - Run
go test -race ./...for concurrency, cache, pipeline, or event changes. - Confirm that source files, comments, tests, and documentation contain only English text.