Task 12: end-to-end integration test - #12
Merged
Merged
Conversation
Runs the shipped script as a subprocess against a real PostgreSQL 16 and checks the bundle it produces. Skipped unless DBPROFILER_POSTGRES_TEST_URL and DBPROFILER_TOKEN_KEY are both set, and named so `python3 -m unittest` never discovers it, so the offline suite stays offline. Fifty tests over one disposable schema: bundle structure and checksums, collection scope, table and column shape, foreign keys and fan-out, Tier 1 telemetry, tokenization, and the negative assertion. The fixtures are seeded so the right answer is computable rather than guessed -- hot orders go to five customer ids disjoint from the evenly spread range, with a stride coprime to it, so exactly 405 parents are referenced; org_id and site_id are correlated into five pairs, so reading the extended statistics gives a different answer from assuming independence. Four values are planted in the fixtures, each reaching the statistics by a different route: a most-common value, a histogram bound, a most-common value on a composite parent, and a utility statement's verbatim text in pg_stat_statements. None may appear in the archive as stored or in any member decompressed. Two further tests prove each plant really is in the source, so a fixture that failed to insert cannot make absence pass for the wrong reason. Three draft assertions were wrong about the tool rather than the reverse, and the corrections are the interesting part: data_type is format_type output, fan-out divides by the child column's distinct count, and p99 is read at the rank the distinct count implies -- so a single hot parent among 376 sits past the 99th percentile without lifting it. Adds TestIntegrationSuiteScope to the unit suite, which parses the new file with ast and fails if a mutating statement does not name the disposable schema, if the schema name stops being unique per run, if drop_fixtures stops being called on both the success and the failure path, or if a credentialed URL or a new token key appears. It earned its place immediately: a mutation-testing step left `DROP SCHEMA IF EXISTS public CASCADE` behind, and the guard caught it from a static parse with no server involved. Extends the safety rule to name the DDL, DML, ANALYZE, CREATE STATISTICS and COUNT(*) this one file needs, scoped to it and to the schema it creates and drops -- the tool reads statistics rather than computing them, so something has to compute them first. Adds a README section listing the deferred scope, so an absent feature is distinguishable from an oversight. Co-Authored-By: roachdev-claude <roachdev-claude-bot@cockroachlabs.com>
`test_dbprofiler.py` has no `from __future__ import annotations`, so the `str | None` return annotation on the new sql_of helper was evaluated at import and raised TypeError on 3.9. Green locally, red on CI's oldest leg. The local check was the problem: `ast.parse(feature_version=(3, 9))` validates syntax and this is not a syntax error. docs/TESTING.md now says to run `python3.9 -m unittest` before committing, and says why the grammar check is not enough. Co-Authored-By: roachdev-claude <roachdev-claude-bot@cockroachlabs.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.
Runs the shipped script as a subprocess against a real PostgreSQL 16 and checks the bundle it produces. Skipped unless
DBPROFILER_POSTGRES_TEST_URLandDBPROFILER_TOKEN_KEYare both set, and named sopython3 -m unittestnever discovers it — the offline suite stays offline.What it covers
50 tests over one disposable schema: bundle structure and checksums, collection scope, table and column shape, foreign keys and fan-out, Tier 1 telemetry, tokenization, and the negative assertion.
The fixtures are seeded so the right answer is computable rather than guessed. Hot orders go to five customer ids disjoint from the evenly spread range, with a stride coprime to it, so exactly 405 parents are referenced.
org_idandsite_idare correlated into five pairs from two orgs and five sites, so reading the extended statistics gives 5 where assuming independence would give 10 — before that change the composite fan-out test would have passed either way.Asserting the negative
Four values are planted in the fixtures, each reaching the statistics by a different route: a most-common value, a histogram bound, a most-common value on a composite parent, and a utility statement's verbatim text in
pg_stat_statements(which PostgreSQL does not normalize to$1). None may appear in the archive as stored or in any member decompressed. Two further tests prove each plant really is in the source, so a fixture that silently failed to insert cannot make every assertion of absence pass for the wrong reason.Three corrections to the draft
Wrong about the tool rather than the tool being wrong, and each worth recording:
data_typeisformat_typeoutput —timestamp with time zone,numeric(12,2)— not the internal type name.Also: the plan's "unsupported JSON/array columns" was wrong.
jsonbandtext[]are both supported, so a fixture built from them would have asserted nothing. Theexotictable carries anint4rangeand aCREATE DOMAINcolumn instead, and the suite asserts both directions.Guarding the guard
TestIntegrationSuiteScopeparsesintegration_test.pywithastand fails if any mutating statement does not name{SCHEMA}, if the schema name stops being unique per run, ifdrop_fixturesstops being called from both the success and the failure path, if a credentialed URL or a new token key appears, or if the file ever becomes discoverable by plainunittest. It earned its place immediately: a mutation-testing step leftDROP SCHEMA IF EXISTS public CASCADEin the file, and the guard caught it from a static parse with no server involved.The token test is itself guarded. Asserting an overlap between the parent's and the child's token lists would also pass if both sides were tokenized under a domain that merely happened to match, so the suite computes the expected token from the key and asserts it is present, then asserts the token the child's own domain would produce is absent.
Mutation testing
DROP SCHEMA→ the new static guard, with no server present.Rule change
.claude/rules/development.mdexempted onlyANALYZEfor disposable fixtures, but multicolumn statistics needCREATE STATISTICS. The exemption now names the DDL, DML,ANALYZE,CREATE STATISTICSandCOUNT(*)this one file needs, scopes it tointegration_test.pyand the schema it creates and drops, and says why — the tool reads statistics rather than computing them, so something has to compute them first. It also forbids comparing the profiler's estimates against a count queried at assertion time, since such a count would agree with an estimator broken in the same direction.Verification
python3 -m unittest— 371 passed (was 363).python3 -m unittest integration_test— 50 passed against PostgreSQL 16.15; 50 skipped when unconfigured.python3 dbprofiler.py --check-safety— OK, 14 SQL constants.ruff check— clean. Parses under the 3.9 grammar.publicschema of the test database verified intact; no fixture schema left behind.README.mdgains a "What this release does not do" section listing the deferred scope, and the status note now says the tool is exercised end to end.