Repository navigation
test(scheduler): make the Lambda no-refresh tests bite again - #971
Merged
Merged
Conversation
Since LeanerCloud#932, ListRecommendations kicks the cold-start and stale-cache collections only for a ctx marked WithBackgroundCollection. The two Lambda tests still read with a plain context.Background(), so nothing was ever collected and they passed with the isLambda guards removed. Run both with WithBackgroundCollection, so the isLambda guard is the only thing that prevents a collect, and stub the first store call each guard skips as optional so a removed guard fails a clear AssertNotCalled. maybeKickBackgroundRefresh's own isLambda guard is unreachable through ListRecommendations (the outer guard returns first) and had no test, so add a direct one with a non-Lambda positive control on the same harness. Test-only; no production change. Closes LeanerCloud#962 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configuration
📒 Files selected for processing: 2
✨ Finishing Touches
Comment |
cristim
reviewed
Oct 16, 2026
cristim
left a comment
Member
There was a problem hiding this comment.
Independent review verdict: CLEAN at 83459e4
Reviewer: fresh Claude agent (Sonnet, high effort), not the author, cold brief. The PR body was treated as a claim. Coordinator: claude-cc-reviewer.
Blocking findings: none. Each test now fails when its isLambda guard is removed, and the same mutants survive on origin/main's tests, which confirms they were vacuous before.
Non-blocking notes:
background_collection_test.go:161: deleting<-releaseas a harness-weakening probe still passed-count=100, so the positive control would not reliably catch a harness regression. The shipped block does make the flag check deterministic.- The Lambda subtest's
time.After(200ms)adds about 0.2s on the pass path. It is not a race, because thecollectingassertion is synchronous. - The two
ListRecommendationstests overlap on the outer guard (scheduler.go:1183). Guard 1452 is covered only by the cold-start test, and guard 1502 only by the new direct test.
What was attacked and how (local macOS, unit tests with mocks):
AWS_CONFIG_FILE=/dev/null AWS_SHARED_CREDENTIALS_FILE=/dev/null go test -race -count=1 ./internal/scheduler/: 199 passed, no SKIP.go test -race -count=50 -run 'Lambda|LambdaGuard' ./internal/scheduler/: 300 passed, with no hang or race.- Mutants: each guard was removed in turn in a scratch worktree and restored after.
- Outer guard (
scheduler.go:1183):LambdaSkipsBackgroundRefreshfails ("GetGlobalConfig was called 1 time(s)... expected none"), andColdStart_Lambdafails too. kickColdStartCollectionguard (:1452):ColdStart_Lambda_NeverMarksOrCollectsfails cleanly onMarkCollectionStarted, with no panic.maybeKickBackgroundRefreshguard (:1502):TestMaybeKickBackgroundRefresh_LambdaGuard/lambda_never_kicksfails, and the non-Lambda control still passes.- The same three mutants all survive on origin/main's test files.
- Outer guard (
- Cleanup:
t.Cleanup(close(release))unblocks the store call.startedis buffered (1), the mock is.Maybe(), and the refresh ends on the post-release error. There was no hang or leak.
Gate:
- Labels are now mirrored from #962.
- CodeRabbit is green.
- CI is still running at this SHA.
- The PR is a draft: please mark it ready when done. It merges once CI is green at this head.
cristim
marked this pull request as ready for review
October 16, 2026 12:23
This was referenced Oct 16, 2026
cristim
pushed a commit
that referenced
this pull request
Oct 16, 2026
…rness (#988) Review follow-up on #971: - The non-Lambda control now hands the blocked store call a value on an unbuffered release channel after asserting the collecting flag is held. If the harness stops blocking, nothing receives and the control fails every run instead of passing by timing. - The Lambda subtest drops its 200ms wait: the guard returns before the synchronous CAS, so the flag check plus a non-blocking receive on started are enough. - Each Lambda test names the isLambda guard it pins. Test-only; no production change. Refs #962 Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.
What was vacuous
Since #932,
Scheduler.ListRecommendationskicks the cold-start and stale-cache collections only when the ctx carriesWithBackgroundCollection(mayCollect := BackgroundCollectionAllowed(ctx)). Two Lambda tests still read with a plaincontext.Background():TestScheduler_ListRecommendations_LambdaSkipsBackgroundRefreshTestScheduler_ListRecommendations_ColdStart_Lambda_NeverMarksOrCollectsWith an unmarked ctx,
mayCollectis false, so nothing is ever collected and both tests pass whether or not theisLambdaguards exist. The probes below show this on theorigin/maintest files.Change (test-only, no production code touched)
internal/scheduler/scheduler_test.go, both tests edited in place:WithBackgroundCollection(context.Background()), so theisLambdaguard is the only thing that stops a collect. Arequire.True(BackgroundCollectionAllowed(ctx))precondition makes the test fail if someone drops the marker again..Maybe():GetGlobalConfig(TTL resolution) for the stale test, andMarkCollectionStartedreturning "lost the race" for the cold-start test. A removed guard then fails the existingAssertNotCalledwith a clear message instead of an unexpected-call panic.internal/scheduler/background_collection_test.go, one new test:TestMaybeKickBackgroundRefresh_LambdaGuard. The issue asked me to check the guards at scheduler.go:~1452 and ~1502. The ~1452 guard (kickColdStartCollection) is now covered by the cold-start test above. The ~1502 guard (maybeKickBackgroundRefresh) can't be reached throughListRecommendations, because the outermayCollect && !s.isLambdacheck returns first, and no test covered it. So the new test callsmaybeKickBackgroundRefreshdirectly. The refresh's first store call blocks until cleanup, so after a wrong kick thecollectingflag (set synchronously by the CAS) is still held when the test checks it. The test doesn't depend on timing to catch a removed guard. A non-Lambda subtest on the same harness is the positive control and must see the refresh start.The new test went into the small
background_collection_test.gorather than the 2.8k-linescheduler_test.go. Nothing was moved, and no existing test covers the same thing.Closes #962
Verification
All commands were run locally on macOS from the worktree with
AWS_CONFIG_FILE=/dev/null AWS_SHARED_CREDENTIALS_FILE=/dev/null. Nothing calls a cloud API, purchases anything, sends email or deploys.Mutation probes (unit evidence; production code mutated, run, then reverted with
git checkout, tree confirmed clean)Run against head
83459e4cwithgo test ./internal/scheduler/ -count=1 -run 'LambdaSkipsBackgroundRefresh|ColdStart_Lambda_NeverMarksOrCollects|TestMaybeKickBackgroundRefresh_LambdaGuard' -v, and the same run with theorigin/mainversions of the two test files restored (fail-before).origin/maintestsListRecommendationsscheduler.go:1183if mayCollect && !s.isLambda {->if mayCollect {LambdaSkipsBackgroundRefreshFAIL (GetGlobalConfig was called 1 time(s) ... expected none).ColdStart_Lambda_NeverMarksOrCollectsalso FAILs (same message).kickColdStartCollectionscheduler.go:1452if s.isLambda {->if false {ColdStart_Lambda_NeverMarksOrCollectsFAIL (MarkCollectionStarted was called 1 time(s) ... expected none)maybeKickBackgroundRefreshscheduler.go:1502if s.isLambda {->if false {TestMaybeKickBackgroundRefresh_LambdaGuard/lambda_never_kicksFAIL (collecting flag set; refresh started on Lambda). The control subtest still PASSes.With no mutation, all three tests PASS. Each guard has at least one test that fails when that guard alone is removed.
Suite, lint and hooks
go build ./...: OKgo vet ./...: OKgo test ./internal/scheduler/... -count=1: okgo test -race ./internal/scheduler/... -count=1: okgo test -race ./internal/scheduler/ -count=100 -run '<the three tests>': okgolangci-lint run --allow-parallel-runners ./internal/scheduler/...(v2.10.1): 0 issuesscripts/gofmt-hook.sh,make tidy-check,scripts/gosec-hook.sh(gosec v2.28.0) on the changed files: all exit 0git-secrets --scanon both changed files with--register-awspatterns (as in CI) plus the repo's.gitallowed: clean. The diff adds no 12-digit literals.gocycloonly looks at non-test files, and none changed.Known-red test on main
When this branch was cut (
b49b494e), main was red onTestScheduler_ListRecommendations_StaleCacheKicksBackgroundRefresh. I confirmed it fails on a cleanb49b494eand left it alone. #960 has since merged (2ef2f5d2) and this branch is rebased onto it, so the whole scheduler package is green at this head.Overlap with #960 / #965
Both of those PRs edit only the
staleListRecommendationshelper (scheduler_test.go ~945). This PR's hunks start at ~1055, and the helper is untouched.b49b494e:git merge-tree --write-tree fix/issue-962 origin/fix/scheduler-stale-refresh-testgave exit 0, clean (e5a050d9).origin/fix/scheduler-stale-kick-test-contextgave exit 0, clean (c5faeebb).go test -race ./internal/scheduler/....origin/fix/scheduler-stale-refresh-test: exit 0, clean.origin/fix/scheduler-stale-kick-test-context: exit 1, conflict in scheduler_test.go at thestaleListRecommendationsctx :=line only.git merge-tree origin/main origin/fix/scheduler-stale-kick-test-contexthits the same conflict, so this is fix(test): mark the stale-refresh test context as an unrestricted reader #965 vs the already-merged test(scheduler): kick the stale refresh with an unrestricted reader #960, not this PR.Labels
I can't apply labels. Could a maintainer mirror #962's labels onto this PR:
impact/internal,triaged,priority/p3,severity/low,urgency/this-quarter,effort/xs,type/bug.🤖 Generated with Claude Code