Skip to content

test(b2): kill surviving Gremlins mutants in reader cancellation (#290) - #294

Merged
ffumero2003 merged 1 commit into
mainfrom
test-b2-issue-290-reader-replication-iterator-mutants
Nov 5, 2026
Merged

ffumero2003 merged 1 commit into
mainfrom
test-b2-issue-290-reader-replication-iterator-mutants

Conversation

@ffumero2003

Copy link
Copy Markdown
Contributor

Context

Address the reader/replication/iterator targets from Part A of #290 on
origin/main (59104c6). Reversing Reader.setErr's first-error guard prevents
cancellation and can strand existing download tests. The other nine specified
mutants are behaviorally equivalent and are skipped below, not suppressed.

Changes

  • Add b2/a_reader_error_test.go, with no network, credentials, timers, or worker
    goroutines. The first error must be retained and cancel the context exactly
    once; a later error must neither replace it nor cancel again.
  • Put the assertion before transfer tests in unshuffled, fail-fast test order so
    the timeout target reports a prompt assertion failure.
  • Change only this reader test file; production and other streams are unchanged.
Target Disposition Exact behavior / equivalence reason
reader.go:111, CONDITIONALS_NEGATION KILLED by the new test Both the nil-error and existing-error branches are asserted. == nil → != nil fails immediately.
reader.go:266, CONDITIONALS_BOUNDARY Equivalent; skipped At available == 0, assigning zero to zero changes nothing.
reader.go:269, CONDITIONALS_BOUNDARY Equivalent; skipped At available == r.length, assigning r.length preserves the same value.
reader.go:286, CONDITIONALS_BOUNDARY Equivalent; skipped At cr == 1, assigning 1 to 1 preserves the worker count.
reader.go:459, CONDITIONALS_BOUNDARY Equivalent; skipped SDK backoff starts at zero, initializes to 1ms, and doubles through 8192ms to 16384ms; the differing 10s equality is unreachable.
replication.go:215, CONDITIONALS_BOUNDARY Equivalent; skipped Equal priorities assign the same current maximum.
replication.go:219, CONDITIONALS_BOUNDARY Equivalent; skipped At max == maxReplicationPriority - 5, fallthrough adds 5 and returns the same maximum as the cap branch.
replication.go:251, ARITHMETIC_BASE Equivalent; skipped len(mapping)+1 → len(mapping)-1 changes only a map allocation hint; all entries are copied unchanged.
iterator.go:102:29, CONDITIONALS_BOUNDARY Equivalent; skipped The surviving > 1000 → >= 1000 comparison assigns 1000 to an existing 1000. The separate < 0 comparison is not this survivor.
iterator.go:108, CONDITIONALS_BOUNDARY Equivalent; skipped At page size 100, assigning 100 to 100 changes nothing.

No tests manufacture unreachable backoff values or assert map allocation details
to claim kills for the equivalent targets. No Part B coverage changes.

Verification

All commands used empty B2_APPLICATION_KEY_ID, B2_APPLICATION_KEY,
B2_ACCOUNT_ID, and B2_ACCOUNT_KEY.

Hand-applied the exact reader.go:111 mutation alone, then restored it. The first
branch red proof from the new test:

=== RUN   TestReaderSetErrKeepsFirstErrorAndCancelsOnce/first_error
recorded error = <nil>, want first download failure
reader context error = <nil>, want context canceled
cancel calls = 0, want 1

The existing-error branch rejects that same mutation too:

=== RUN   TestReaderSetErrKeepsFirstErrorAndCancelsOnce/existing_error
recorded error = later download failure, want first download failure
cancel calls = 1, want 0
FAIL github.com/Backblaze/blazer/b2 0.511s

The mutated full package also fails promptly with
go test -count=1 -failfast -timeout=20s ./b2:

--- FAIL: TestReaderSetErrKeepsFirstErrorAndCancelsOnce (0.00s)
    --- FAIL: TestReaderSetErrKeepsFirstErrorAndCancelsOnce/first_error (0.00s)
FAIL github.com/Backblaze/blazer/b2 0.313s

After restoring the production guard, the focused test passes:

--- PASS: TestReaderSetErrKeepsFirstErrorAndCancelsOnce (0.00s)
    --- PASS: TestReaderSetErrKeepsFirstErrorAndCancelsOnce/first_error (0.00s)
    --- PASS: TestReaderSetErrKeepsFirstErrorAndCancelsOnce/existing_error (0.00s)
PASS
ok github.com/Backblaze/blazer/b2 0.324s
  • go build ./...: PASS, no output.
  • go vet ./...: PASS, no output.
  • go test ./b2/...: PASS (b2 11.482s; b2/sync 2.761s).
  • gofmt -l .: clean.
  • make ci: PASS, including lint (0 issues), race/shuffle tests, module
    checks, b2keys, cross-compiles, changelog check, and script tests. The b2 race
    suite passed in 20.021s.
  • Fresh review of the final diff and mutation claims: no blocking findings.
  • No Gremlins rerun; the proof is the exact hand-applied mutation and restored
    green run. Equivalent mutants were reviewed and skipped, not reported killed.
  • Live B2 and simulator checks: NOT RUN. This tests reader error bookkeeping and
    cancellation without changing production request behavior or harness scenarios.

Actual make ci tail (exit 0):

ok   skips finished tests in a failed package
ok   keeps the error line after long failure output
ok   keeps the last lines of long failure output
ok   says how many lines were omitted
ok   keeps the timeout reason above a long stack trace
ok   keeps a timeout reason that follows 150 progress lines
ok   keeps the failure of the first of three failing tests
ok   keeps the failure of the quiet test between two noisy ones
ok   keeps the failure of the last of three failing tests

Part of #290

Assert that the first download error is retained and cancels once, while a later error neither replaces it nor cancels again. Run this deterministic check before transfer tests in unshuffled mutation runs.

Part of #290
@ffumero2003 ffumero2003 self-assigned this Nov 5, 2026
@ffumero2003
ffumero2003 merged commit 3bbd258 into main Nov 5, 2026
27 of 28 checks passed
@ffumero2003
ffumero2003 deleted the test-b2-issue-290-reader-replication-iterator-mutants branch November 5, 2026 22:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant