diff --git a/docs/how-to.md b/docs/how-to.md index 430160a6..d8803ed6 100644 --- a/docs/how-to.md +++ b/docs/how-to.md @@ -384,6 +384,7 @@ Both sketch types can be stored in a columnar table, for example one sketch per day. A stored `hll` comes back byte for byte, so `hll_union_agg` over the daily sketches counts what one sketch over all the rows counts. +## Manage time partitions with pg_partman pg_partman can create and drop columnar partitions. It needs one setting to do so, and without it the partitions it makes are not columnar. diff --git a/test/docs_style.sh b/test/docs_style.sh index 64ad2778..9bdb5505 100755 --- a/test/docs_style.sh +++ b/test/docs_style.sh @@ -126,6 +126,16 @@ conflicts=$(grep -rlE '^(<<<<<<< |>>>>>>> )' "$SRCDIR/docs" "$SRCDIR"/*.md 2>/de check "no document carries a merge conflict marker" \ "$([ -z "$conflicts" ] && echo none || echo "$conflicts")" "none" +# THE pg_partman HOW-TO KEEPS ITS OWN HEADING. An edit that inserted a section +# before it replaced the heading instead (3627327, #1315), and every check here +# passed: the steps were still valid Markdown, now filed under "Count distinct +# values and percentiles approximately". The section is found by its heading and +# must open with the pg_partman paragraph its steps belong to. +partman_open="$(awk '$0 == "## Manage time partitions with pg_partman" {f=1; next} + f && NF {print; exit}' "$SRCDIR/docs/how-to.md")" +check "the how-to keeps its pg_partman section under its own heading" \ + "$(printf '%s' "$partman_open" | grep -c '^pg_partman can create and drop columnar partitions')" "1" + # CHANGELOG.md: dash characters only. See the scope note above. dashes=$(grep -c '—\|–' "$SRCDIR/CHANGELOG.md" || true) check "CHANGELOG.md carries no em or en dash" "$dashes" "0" diff --git a/test/pytest/TESTS.md b/test/pytest/TESTS.md index 696c2985..c67625de 100644 --- a/test/pytest/TESTS.md +++ b/test/pytest/TESTS.md @@ -140,6 +140,7 @@ behaviour, the source of that number is named. - [92. test_tid_range_scan.py: a ctid range reads only the row groups that hold it](#92-test_tid_range_scanpy-a-ctid-range-reads-only-the-row-groups-that-hold-it) - [93. test_partition_lifecycle.py: partition_create_ahead keeps a time-partitioned parent ahead of now](#93-test_partition_lifecyclepy-partition_create_ahead-keeps-a-time-partitioned-parent-ahead-of-now) - [94. test_approx_aggregates.py: hll and tdigest over columnar tables, the compatibility statement](#94-test_approx_aggregatespy-hll-and-tdigest-over-columnar-tables-the-compatibility-statement) +- [95. test_docs_how_to_sections.py: the pg_partman how-to keeps its own heading](#95-test_docs_how_to_sectionspy-the-pg_partman-how-to-keeps-its-own-heading) ## 1. How to read a test in here @@ -6556,3 +6557,15 @@ hll 2.19 does not build against PostgreSQL 19, so `test_hll_over_columnar` is `U | --- | --- | | `test_tdigest_over_columnar` | the columnar table returns every row written; the tdigest aggregate reads through the columnar scan; its p99 over columnar equals heap's exactly; within 0.1% of the exact percentile; a tdigest stored per day in a columnar table still answers within 0.1% | | `test_hll_over_columnar` | the hll aggregate reads through the columnar scan; the sketch over columnar is byte-identical to heap's; the estimate is within 6.9% of the exact count; a stored hll comes back byte for byte, and the union of daily sketches counts what one sketch counts | + +## 95. test_docs_how_to_sections.py: the pg_partman how-to keeps its own heading + +An edit that inserted the approximate-aggregates section before the pg_partman how-to replaced its heading instead (3627327, #1315). Every docs check passed, because the steps were still valid Markdown, filed under "Count distinct values and percentiles approximately". The pytest half of the docs_style.sh arm of the same name, written independently: it splits the how-to on its level-two headings and reads the section's first paragraph. It needs no cluster, so it is in `NO_CLUSTER`. + +Red on main at d208bce in both twins (got 0, want 1); green with the heading restored. + +### Every test + +| test | what it holds | +| --- | --- | +| `test_the_how_to_keeps_its_pg_partman_section_under_its_own_heading` | the how-to has a "Manage time partitions with pg_partman" section, and it opens with the pg_partman paragraph its steps belong to | diff --git a/test/pytest/expected_tests.txt b/test/pytest/expected_tests.txt index 641b495b..b639554b 100644 --- a/test/pytest/expected_tests.txt +++ b/test/pytest/expected_tests.txt @@ -268,7 +268,8 @@ # guard_tests 412 -> 413 for test_a_missing_dependency_of_pyarrow_fails_rather_than_declines # (#1286 review), collected over the NO_CLUSTER files on this tree. # guard_tests 413 -> 414 for #1305's test_an_unguarded_import_is_refused_under_xdist_too, by collection. -guard_tests 414 +# guard_tests 414 -> 415 for test_docs_how_to_sections.py (the lost pg_partman heading), by collection. +guard_tests 415 # The complement: tests that need the driver and a throwaway cluster. Until #1016 these ran # in no CI job at all -- a quarter of the corpus, green when somebody ran them by hand and diff --git a/test/pytest/test_docs_how_to_sections.py b/test/pytest/test_docs_how_to_sections.py new file mode 100644 index 00000000..458fe35a --- /dev/null +++ b/test/pytest/test_docs_how_to_sections.py @@ -0,0 +1,29 @@ +"""The pg_partman how-to keeps its own heading. + +An edit that inserted a section before it replaced the heading instead (3627327, +#1315), and every docs check passed: the steps were still valid Markdown, filed +under "Count distinct values and percentiles approximately". + +The pytest half of the docs_style.sh arm of the same name, written independently: +it splits the how-to on its level-two headings and reads the section's first +paragraph. + +Needs the repository only, not a cluster or the driver. +""" +import pathlib +import re + +HOWTO = pathlib.Path(__file__).resolve().parents[2] / "docs" / "how-to.md" + + +def _sections(): + """-> {heading text: body} for every '## ' section of the how-to.""" + parts = re.split(r"^## (.+)$", HOWTO.read_text(), flags=re.M) + return {parts[i].strip(): parts[i + 1] for i in range(1, len(parts) - 1, 2)} + + +def test_the_how_to_keeps_its_pg_partman_section_under_its_own_heading(expect): + body = _sections().get("Manage time partitions with pg_partman", "") + first = next((p.strip() for p in body.split("\n\n") if p.strip()), "") + expect.num(1 if first.startswith("pg_partman can create and drop columnar partitions") else 0, 1, + "the how-to keeps its pg_partman section under its own heading") diff --git a/test/pytest/test_harness_deps.py b/test/pytest/test_harness_deps.py index d5b16c95..d7505b7d 100644 --- a/test/pytest/test_harness_deps.py +++ b/test/pytest/test_harness_deps.py @@ -73,6 +73,7 @@ "test_suite_accounting.py", # #1288: reads docs/*.md and README.md only. "test_docs_cross_database_query.py", + "test_docs_how_to_sections.py", # #1215: inner pytest runs of expect.declines and require_module. Needs no # cluster and no driver; it never reaches into the shell harness. "test_capability_decline.py",