Repository navigation
test(analytics): fold the hand-rolled ConfigStore mock onto mocks.MockConfigStore - #1254
Conversation
…kConfigStore The analytics collector test carried a 145-method copy of config.StoreInterface, so every new store method needed a stub there as well as in internal/mocks. The collector only reads GetActivePurchaseHistory, so the test double now embeds the shared MockConfigStore and overrides just that method; the four other func fields it carried were never set by any test. Add a repo-wide guard in internal/mocks that fails when a _test.go type defines more than half of StoreInterface's methods, so a new full copy cannot appear. internal/server's mockConfigStoreForHealth is allowlisted until it is folded the same way; the allowlist fails on stale entries, so it can only shrink. Refs LeanerCloud#76 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reached
This review includes 2 billable files and costs up to $0.50. Or wait 59 minutes for your next included review. View limit details
Comment |
Bring the branch up to date with main. Conflicted files: - internal/analytics/collector_test.go: main kept adding stubs to the hand-rolled analytics mockConfigStore (HistorySummaryAggregate from LeanerCloud#1200, ClaimCollectionInvocation from LeanerCloud#1099, the ReplaceRecommendations removal from LeanerCloud#1209, and the pgx import they need). This branch replaces that hand-rolled mock with one that embeds mocks.MockConfigStore, which already carries all of those methods on main. Kept the branch's version; main's stub edits are covered by the shared mock and drop out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bring the branch up to date with main again; main moved on while the previous merge was being checked. Conflicted files: - internal/analytics/collector_test.go: main (LeanerCloud#1242) added a CancelExecutionAtomicTokenPinned stub to the hand-rolled analytics mockConfigStore. This branch replaces that mock with one embedding mocks.MockConfigStore, which main already gives the same method. Kept the branch's version; the stub is not needed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Merged origin/main into this branch twice: first 8f186a8, then c1f1781, because main moved while the first merge was being checked. New head: 9e7fd37. Conflict resolution (both merges, same file):
Checks on the merged head:
|
|
Independent review (IAmJSD's agent, fresh context, given only the diff, the issue and the PR text): VERDICT: REQUEST_CHANGES Blocking:
Non-blocking:
Attacked:
Body-stale:
Reviewer: rB12. Bar while the maintainers are away (set by IAmJSD as acting owner): one approving independent review on the head, two for money, auth and security paths. |
Brings the branch up to date with main so the PR is mergeable again. Conflicted files: - internal/analytics/collector_test.go: main edited the hand-rolled mockConfigStore stubs this branch deletes. LeanerCloud#1299 added GetMarketplaceListingAttempt and ResolveMarketplaceListingAttempt, and LeanerCloud#1217 removed GetPendingExecutionsTx. The branch's version is kept, where mockConfigStore embeds mocks.MockConfigStore and overrides only GetActivePurchaseHistory. Main's two PRs made the matching changes to mocks.MockConfigStore, so the embedded mock already has the new methods and lacks the removed one. The file is identical to the branch head. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Merged current main into the branch. New head: 091c979.
Checks:
|
|
Independent review (IAmJSD's agent, fresh context, given only the diff, the issue and the PR text): VERDICT: APPROVE Blocking:
Non-blocking:
Attacked:
Body-stale:
Reviewer: rB18. Bar while the maintainers are away (set by IAmJSD as acting owner): one approving independent review on the head, two for money, auth and security paths. |
|
Local verification at |
|
Merged by IAmJSD's agent at IAmJSD's request (IAmJSD is acting owner while the maintainers are away), under the bar IAmJSD set: 1 approving independent review(s) on |
Conflict: internal/analytics/collector_test.go. LeanerCloud#1254 folded the hand-rolled analytics mock onto mocks.MockConfigStore, so took main's file and dropped this branch's two stubs there; the shared mock already carries them from this branch's internal/mocks/stores.go change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
LeanerCloud#1254 (on main) replaced the hand-rolled config-store mock in collector_test.go and dropped the now-unused pkg/common import. This branch's new commitment-type assertion uses common.CommitmentType, so the analytics test build broke after main was merged in although the merge was textually clean. Same assertion. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Root cause
Three test doubles implemented the whole of
config.StoreInterface(145 methods) by hand:internal/mocks.MockConfigStore,internal/analytics.mockConfigStoreandinternal/server.mockConfigStoreForHealth. Each new store method therefore needed a stub in all three places. Nothing stopped a fourth copy from appearing.Fix (first slice)
internal/analytics/collector_test.go:mockConfigStorenow embedsmocks.MockConfigStoreand overrides onlyGetActivePurchaseHistory, the one config-store read the collector makes (collector.go:96). The default staysnil, nil, as before. 527 lines of stubs are gone. The four other func fields (getPurchaseHistoryFunc,getAllPurchaseHistoryFunc,getPurchaseHistoryByPurchaseIDFunc,markPurchaseRevokedFunc) were never set by any test, so they go too. No test call site changed.internal/mocks/config_store_copies_guard_test.go(new): a repo-wide syntactic guard,TestNoHandRolledConfigStoreMocks. It reads theStoreInterfacemethod set frominternal/config/interfaces.go. It fails when any type declared in a_test.gofile defines more than half of those methods. Today the largest partial override defines 24 of 145 (internal/server.mockConfigStoreForExchange), and the threshold is 73, so there is plenty of margin.internal/server.mockConfigStoreForHealthis allowlisted until it is folded. The allowlist can only shrink: the guard fails if an entry no longer hand-rolls the interface or no longer exists.No production code changed.
internal/mocks/stores.gois untouched, to keep conflicts with the open branches that add store methods to a minimum.Refs #76
Verification
All of this is unit/mock evidence. The change is test-only.
Fail-before / pass-after for the guard:
internal/analytics/collector_test.gorestored:go test ./internal/mocks/ -run TestNoHandRolledConfigStoreMocksFAILS and reportsinternal/analytics.mockConfigStoreas a hand-rolledconfig.StoreInterfacetest double.Mutation probes:
mockConfigStoreForHealthis now reported as a copy.GetActivePurchaseHistoryoverride from the analytics wrapper makesTestCollectorCollectFAIL with a panic. The shared mock dispatches that method throughm.Calledwithout a default, so the wrapper's override really is what the collector tests exercise.No non-test Go files changed, so gocyclo has nothing to check.
Combined-tree verification. This branch was tested together with six other queued branches on a local, never-pushed tree:
queue/platform@77d116c6= origin/maina14dc8f2plus these heads, merged in this order:Linux, Go 1.26.9,
AWS_CONFIG_FILE=/dev/null AWS_SHARED_CREDENTIALS_FILE=/dev/null AWS_EC2_METADATA_DISABLED=true; Docker Postgres via testcontainers:go build ./...,go vet ./...,go vet -tags integration ./...and the fullgo test -race -short -count=1 ./....--build-tags integration, andgocyclo -over 10is silent on the changed non-test files. These ran atb61a9c30, which differs from77d116c6only by one.gitallowedline on fix/issue-1233.-tags integration -count=1):cmd/cleanup-lambda,internal/analytics,internal/auth,internal/database/postgres/migrationsandinternal/purchase.internal/apipasses, except two tests whose Postgres container didn't start, or whose migrations hit a timeout, under machine load. Rerun alone on the same tree, both pass:TestDeleteManagedPlanByExecutionStatusandTestNotifiedRow_RescheduleDoesNotOverwriteConcurrentCancel.internal/configpasses exceptTestPostgresStoreDB_ResolveStaleRIExchange_ValidatesCloudCheck, which fails the same way on unmodified main (fixed by fix(config): compare resolve checked_at at the database's microsecond precision #1252).TESTCONTAINERS_RYUK_DISABLED=trueto avoid a testcontainers reaper race under load.scripts/setup-git-secrets.shpatterns in a fresh repo with an isolated HOME, found nothing in the changed files, and a planted fake key was flagged.scripts/test-git-secrets-allowlist.sh: 137 PASS, 0 FAIL.Out of scope / remaining for #76
internal/server/test_helpers_test.gomockConfigStoreForHealth(145 methods, about 520 lines) still needs folding. It is left for a follow-up to keep this diff small. It needs more care than the analytics copy:MockConfigStoremethods (for exampleGetServiceConfig,SaveGlobalConfig,GetPendingExecutions,GetRIExchangeDailySpend,ReserveRIExchange) callm.Calledunconditionally, so they panic when no expectation is set.handler_ladder_test.go,handler_ri_exchange_test.go) rely on that implicitly.handRolledConfigStoreAllowlistand change this toCloses #76.MockHTTPClient, underproviders/azure/...) belongs to thecloud-commitments-gorepository. That code does not exist in this repo, so it is not addressed here.Maintainer: please mirror the issue's triage labels on this PR:
impact/internal,type/chore,triaged,priority/p3,severity/low,urgency/this-quarter,effort/m.🤖 Generated with Claude Code