Repository navigation
test(analytics): verify account-filter semantics on real Postgres - #1154
Conversation
The analytics integration tests were remapped mechanically from the removed single-string account argument, and every row they saved belonged to one account, so a predicate that matched the wrong column, dropped a column, lost the provider scope or ignored the filter still passed them. Add a dual-column account-filter suite that seeds UUID-only, external-only, both-column, same-number-other-provider and other-tenant rows and asserts the exact matched set through QuerySavings, QueryByProvider, QueryByService and QueryMonthlyTotals for each resolver call shape. Narrow the remapped provider keys to the providers each existing test actually saved, and replace the vacuous NotNil/NotEmpty assertions on the monthly and by-provider tests with the exact rows. Closes LeanerCloud#32 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reached
This review includes 3 billable files and costs up to $0.75. Or wait 59 minutes for your next included review. View limit details
Comment |
|
VERDICT: APPROVE c04ba4b Reviewed: Findings
Contract check after #1161: the store predicate (internal/analytics/postgres_analytics.go:53-80) is unchanged on main. #1161 changed only which filter the API builds; every shape it can emit (UUID plus provider-scoped ext, provider-scoped ext only, Attacked:
|
|
Independent review 2 (claude-fleet, cold): APPROVE c04ba4b This is a test-only PR, and it does what #32 asks. On real Postgres the new suite fails under every filter mutation I tried, and the full package passes on head and on the head merged with origin/main. Findings (none blocking):
Attacked:
Verified locally, with no cloud credentials, under the heavy lock, on the repo's testcontainers harness:
Reviewed by an independent agent with no author context (second reviewer). Review only: nothing was pushed, and the GitHub review state is unchanged. |
|
Local verification at
|
|
Marked ready and merged by IAmJSD's agent, at IAmJSD's request, after 2 independent reviews and local verification (see the review and verification comments above, all at |
Summary
Test-only change; no production code is touched.
The
internal/analyticsintegration tests were remapped mechanically from the removed single-string account argument to a blanketAccountExternalIDsByProvider: {"aws": {...}, "gcp": {...}}and had never been checked at runtime. Every row they saved belonged to one external account and carried nocloud_account_id, so the only account-filter mutation they could catch was "match everything" (through the two non-existent-account cases). If the predicate matched the wrong column, dropped the UUID half, lost the per-provider scope, mishandled the legacy""provider key, or a singleQuery*method ignored the filter, the suite still passed. The monthly-totals test only assertedNotNil(its comment said the view "may be empty", which is wrong: the refresh is synchronous), so an empty result passed too.Changes
New
postgres_analytics_account_filter_db_test.go(TestPostgresAnalyticsStore_AccountFilterSemantics_DB). One container with twocloud_accountsrows and six snapshots. Each snapshot hits exactly one part of the dual-column predicate or is a decoy:cloud_account_idNULL (the ambient/legacy shape)account_idholds a number no filter names)gcpEvery row has its own service, so it is its own bucket in every query. Each case asserts the exact set of matched rows through all four methods:
QuerySavings,QueryByProvider,QueryByServiceandQueryMonthlyTotals(after a real matview refresh). The cases are the call shapesresolveSingleAccountFilterIDs/resolveAccountFilterIDsactually produce:""keyExisting
postgres_analytics_db_test.go/postgres_analytics_integration_test.go(the same edits in both; the files are near-duplicates):QueryByService,BulkInsertSnapshotsandQueryMonthlyTotalssave onlyawsrows, so they now key onlyaws. TheQuerySavingsandQueryByProviderfixtures save bothawsandgcprows under the same number, so they keep both keys.AccountUUIDsvsAccountExternalIDsByProvider: these fixtures save an external id and nocloud_account_id, so the external-id map is the correct filter for them. UUID matching is now covered by the new suite.QueryMonthlyTotals:NotNilbecame an exact single-row check: account, nil cloud account, provider, service, savings and snapshot count.QueryByProvider:NotEmptybecameLen 2, plus the gcp bucket's value, so thegcpkey is shown to match.Verification
All of this is local integration evidence on real PostgreSQL 16 (testcontainers, Docker 28.2.2) on macOS. The
Query*calls were invoked directly; the HTTP handler and real cloud accounts were not part of the runs.AWS_CONFIG_FILE=/dev/null AWS_SHARED_CREDENTIALS_FILE=/dev/null go test -tags=integration ./internal/analytics/ -count=1 -v: all pass, 0 skips. Also passes with-race. Run before the change too: the existing suite passed, with 0 skips.internal/analytics/postgres_analytics.goand then reverted. The DB tests ran against the origin/main test files ("old") and against this branch ("new"). The harness also checked free disk before each run.cloud_account_id = ANY(uuids)halfaccount_id(the wrong-column trap)""provider key (falls through toTRUE)""as a literalprovider = ''QueryByProviderignores the account filterQueryByServiceignores the account filterQueryMonthlyTotalsdrops the UUID halfQueryMonthlyTotalsmatches the external id againstcloud_account_idQueryByProviderhonors only the first provider keyQuerySavingsignores the account filterThe old suite caught 2 of 12; the new one catches all 12. M10 and M11 are localized on purpose, to show that the strengthened monthly and by-provider assertions in the existing files catch a mutation the old ones missed.
go build ./...;go vet ./internal/analytics/with and without-tags=integration.go test ./internal/analytics/ ./internal/mocks/ ./internal/database/postgres/testhelpers/ -count=1passes. The last package is the chore(iac): drop deploy-role grants left unused by retiring the cleanup functions #1597 skip guard, which also parses the new file.--allow-parallel-runners, with and without--build-tags integration) on./internal/analytics/...: 0 issues.gocyclo -over 10 -ignore "_test\.go" internal/analytics/: silent. No non-test code changed.scripts/setup-git-secrets.shwas run in a freshgit initcopy of the tracked files with an isolated HOME.--scanis clean, and a probe line confirmed the AWS account-ID detector fires. The new 12-digit placeholders are namedacct*so they don't trip it.scripts/test-git-secrets-allowlist.sh: 42 PASS, 0 FAIL.-tests -tags integration) on./internal/analytics/: no findings.~/.aws/configdefault profile is invalid. They don't affect these tests.Concurrency: no schema, migration or write-path change, so no new race is plausible. The suite gives each test its own container.
Out of scope
postgres_analytics_db_test.goandpostgres_analytics_integration_test.goare near-duplicates (same cases; one usesRequirePostgresContainerplus theSKIP_DB_TESTSopt-out, the other usesSetupPostgresContainer). Merging them is left for a separate cleanup.postgres_analytics_db_test.gois also over the 500-line guideline, which is why the new suite is a separate file.internal/api/analytics_postgres.gohas its own copy ofaccountFilterClauseon thepurchase_historypath. This PR does not cover it.Closes #32
Maintainers: please mirror the issue's triage labels onto this PR:
priority/p2,severity/low,urgency/this-quarter,impact/internal,effort/m,type/chore,triaged.🤖 Generated with Claude Code