Skip to content

Expanded automated test coverage across the E2E journey suite - #61

Merged
vyruss merged 9 commits into
mainfrom
test/automate-functional-tcs
Jul 28, 2026
Merged

Expanded automated test coverage across the E2E journey suite#61
vyruss merged 9 commits into
mainfrom
test/automate-functional-tcs

Conversation

@imtiazqa

Copy link
Copy Markdown
Collaborator

Added following test cases:

  1. Cold data confirmed in Iceberg via metadata: Verify a Parquet file exists in SeaweedFS after archive
  2. Storage secret not exposed in pg_dump: Verify credentials are excluded from database dumps
  3. Lakekeeper warehouse wrong credentials rejected: Verify S3 credential validation at warehouse creation
  4. SeaweedFS restart cold data persists: Verify cold data survives SeaweedFS container restart
  5. PostgreSQL restart extensions and DuckDB secret reload: Verify coldfront and pg_duckdb reload correctly after DB container restart
  6. Partition column timestamp without time zone: Verify tiering works with timestamp (no tz) partition column
  7. Partition column date type: Verify tiering works with date partition column
  8. Partition column unsupported type text rejected: Verify archiver rejects tables with non-time, non-id partition columns
  9. Timestamp no tz round-trip through Iceberg: Verify col_timestamp stores and retrieves without timezone shift
  10. Time round-trip through Iceberg: Verify col_time stores and retrieves correctly
  11. Character N round-trip through Iceberg: Verify col_char stores with padding and retrieves correctly
  12. JSON round-trip through Iceberg: Verify col_json stores as VARCHAR and retrieves via key operator
  13. Interval round-trip through Iceberg: Verify interval stores as VARCHAR and retrieves correctly
  14. OID widens to bigint in Iceberg: Verify oid stores as BIGINT in Iceberg and returns correctly
  15. All supported types visible in unified view after archive: Verify every column of the archived row matches the inserted value
  16. Archive multiple tables one table fails others continue: Verify archiver exits non-zero on failure and documents which table failed
  17. List shows all registered tables with correct config: Verify partitioner list displays all registered tables with their individual lifecycle values
  18. Disable one table archiver skips it processes others: Verify disabled table is excluded from archiver while others run normally
  19. Register same table twice idempotent update: Verify re-registering a table updates values without creating a duplicate row
  20. Register UNLOGGED partitioned table expected rejection: Verify archiver rejects UNLOGGED tables with a clear error
  21. Register TEMPORARY table expected rejection: Verify TEMP tables are invisible across sessions and rejected at register time
  22. Flat LIST partitioned table archiver rejects at archive time: Verify LIST table accepted at register but fails at archive with bound-parse error
  23. HASH partitioned table archiver rejects at archive time: Verify HASH table accepted at register but fails at archive with bound-parse error
  24. Same table name in two schemas schema-qualified Iceberg names: Verify two same-named tables in different schemas produce distinct non-colliding Iceberg paths

Muhammad Imtiaz added 5 commits July 28, 2026 12:31
…089/092/096/098/099/105/107/108/109/110/113/114/115/116/138 in journey.sh

Coverage:
- TC-043: iceberg_metadata() Parquet file probe
- TC-058: pg_dump excludes S3/GCS/Azure credentials
- TC-059: Lakekeeper rejects bad-credential warehouse request
- TC-062: cold rows survive SeaweedFS container restart
- TC-063: PG extensions and DuckDB secret reload after pg restart
- TC-066/067/070: partition column types (timestamp no-tz, date, text rejected)
- TC-087/089/092/096/098/099/105: extended type round-trips (timestamp, time, char, json, interval, oid, full-column-set)
- TC-107/108/109: multi-table isolation (failure, list config, disable-one)
- TC-110: idempotent re-register updates config, no duplicate row
- TC-113/114: unsupported table types (UNLOGGED, non-existent) rejected at register
- TC-115/116: LIST and HASH partition strategies rejected at archive time
- TC-138: same table name in two schemas yields distinct Iceberg namespaces
…gged register behavior, partition PK inheritance, and bound-parse grep patterns
@imtiazqa
imtiazqa requested a review from vyruss as a code owner July 28, 2026 12:42
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@vyruss, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 50 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0db63db5-af45-4257-97ab-5a91acff1fd2

📥 Commits

Reviewing files that changed from the base of the PR and between 390a073 and b5a1b90.

📒 Files selected for processing (1)
  • ci/journey.sh
📝 Walkthrough

Walkthrough

Changes

Tiered journey coverage

Layer / File(s) Summary
Deterministic archive setup
ci/journey.sh
Adds shared hot-tier cutoff and archive-isolation helpers, and reuses the cutoff calculation across existing stories.
Tiered storage and archiving stories
ci/journey.sh
Adds end-to-end coverage for cold Iceberg metadata, secrets, credentials, restarts, types, partitioning, multi-table behavior, invalid tables, and schema collisions.
Tiered story orchestration
ci/journey.sh
Runs the new stories in the tiered-mode sequence before the existing restart and drop-related stories.

Estimated code review effort: 4 (Complex) | ~60 minutes

Suggested reviewers: vyruss

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: expanded E2E journey test coverage.
Description check ✅ Passed The description is clearly related and lists the added E2E test cases.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/automate-functional-tcs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (8)
docs/animated_diagram.html (4)

752-753: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

currentStepIndex is dead state.

It's declared here and assigned in runAction (Line 903) but never read. Drop it, or wire it into the flows if step tracking was intended.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/animated_diagram.html` around lines 752 - 753, Remove the unused
currentStepIndex state declaration and its assignment in runAction, unless step
tracking is intentionally required; do not alter the surrounding activeTimeline
flow.

868-872: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Label the play/pause button for assistive tech.

The button's only content is a glyph, so it has no meaningful accessible name and its state isn't exposed.

♿ Proposed fix
     function togglePlay() {
       isPlaying = !isPlaying;
-      document.getElementById('play-pause').innerText = isPlaying ? "⏸" : "▶";
+      const btn = document.getElementById('play-pause');
+      btn.innerText = isPlaying ? "⏸" : "▶";
+      btn.setAttribute('aria-label', isPlaying ? 'Pause simulation' : 'Play simulation');
       logToConsole(isPlaying ? "Simulation resumed." : "Simulation paused.");
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/animated_diagram.html` around lines 868 - 872, Update togglePlay so the
play-pause button exposes a meaningful accessible label that reflects its
current state, such as “Pause” while playing and “Play” while paused, alongside
the existing glyph and console logging behavior.

553-560: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Give the speed slider an accessible name.

The "Slower"/"Faster" spans aren't programmatically associated, so the range input is announced without a label.

♿ Proposed fix
-          <input type="range" class="speed-slider" id="speed-range" min="1" max="10" value="5" oninput="updateSpeed()">
+          <input type="range" class="speed-slider" id="speed-range" min="1" max="10" value="5"
+                 aria-label="Animation speed" oninput="updateSpeed()">
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/animated_diagram.html` around lines 553 - 560, Give the range input in
the animation-controls block an accessible programmatic name by associating it
with a visible label or adding an appropriate accessible naming attribute.
Preserve the existing slider behavior and “Slower”/“Faster” visual guidance.

633-646: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Tooltips are mouse-only.

showTooltip/hideTooltip are bound to onmouseover/onmouseout on non-focusable <g> elements, so keyboard and screen-reader users can never reach the component descriptions. Consider adding tabindex="0" plus onfocus/onblur handlers on each node group (and positioning off getBoundingClientRect() of the node when the event has no cursor coordinates).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/animated_diagram.html` around lines 633 - 646, The node groups
node-client and node-hook are only tooltip-accessible by mouse. Make each group
keyboard-focusable with tabindex="0", add matching onfocus and onblur handlers
that invoke showTooltip and hideTooltip, and ensure tooltip positioning falls
back to the focused node’s getBoundingClientRect() when no cursor coordinates
are available; apply the same accessibility behavior to every node group in the
diagram.
ci/journey.sh (4)

3180-3189: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Top comment and step() message contradict each other on the expected rejection point.

The block header (line 3181) states the story is about "UNLOGGED partitioned table rejected at register," but the step() message inside the function (line 3186) says "register accepted; fails at archive time." The implementation itself is intentionally lenient about which stage rejects (using note for the unexpected path), so the header title is misleading about what's actually being asserted.

📝 Align header with actual behavior
-# Story — TC-113: UNLOGGED partitioned table rejected at register.
+# Story — TC-113: UNLOGGED partitioned table — rejected at register or archive.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ci/journey.sh` around lines 3180 - 3189, Align the TC-113 story header
comment with the behavior described by step() in story_unlogged_rejected: state
that registration is accepted and rejection occurs at archive time. Do not
change the implementation or its intentionally lenient stage handling.

2719-2743: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

bash -c with interpolated ${SW_IP} re-parses a variable as shell code.

Static analysis flags this as CWE-78 (OS command injection pattern): bash -c ">/dev/tcp/${SW_IP}/8333" re-parses the interpolated string as a new shell command. In practice SW_IP looks like it's derived from Docker network inspection (not attacker input), so exploitability here is minimal, but the pattern is worth avoiding for defensive hygiene — a subshell redirection avoids the re-parse entirely:

🛡️ Safer TCP-check pattern
-    until bash -c ">/dev/tcp/${SW_IP}/8333" 2>/dev/null; do
+    until (exec 3<>"/dev/tcp/${SW_IP}/8333") 2>/dev/null; do
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ci/journey.sh` around lines 2719 - 2743, Replace the interpolated bash -c TCP
probe in story_seaweedfs_restart with a direct subshell redirection to /dev/tcp
using SW_IP, avoiding re-parsing the address as shell code. Preserve the
existing retry counter, timeout, failure message, and post-readiness delay.

Source: Linters/SAST tools


3316-3334: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Unquoted heredoc requires manual \$ escaping, unlike every sibling story.

This heredoc uses <<EOSQL (unquoted), forcing the PL/pgSQL dollar-quote delimiters to be manually escaped (\$do\$ at lines 3323 and 3331) to avoid bash treating $do$ as variable expansion. Every other SQL heredoc added in this PR (TC-066, TC-067, TC-107, TC-109) uses the safer <<'EOSQL' (quoted) form, which needs no escaping since no shell variables are actually referenced in this block. Using the quoted form here would be more consistent and remove the risk of a missed backslash silently breaking the SQL or (in the worst case) triggering unintended expansion if a $-prefixed name is ever added later.

♻️ Use the same quoted-heredoc convention as sibling stories
-    qf "$HOST" <<EOSQL >/dev/null
+    qf "$HOST" <<'EOSQL' >/dev/null
 CREATE TABLE IF NOT EXISTS public.sa_items (
...
-DO \$do\$
+DO $do$
 DECLARE m date;
 BEGIN
   m := (date_trunc('month', now()) - interval '2 months')::date;
   EXECUTE format('CREATE TABLE IF NOT EXISTS public.%I PARTITION OF public.sa_items FOR VALUES FROM (%L) TO (%L)',
                  'sa_items_p_' || to_char(m, 'YYYY_MM'), m, (m + interval '1 month'));
   EXECUTE format('CREATE TABLE IF NOT EXISTS sc2.%I PARTITION OF sc2.sa_items FOR VALUES FROM (%L) TO (%L)',
                  'sa_items_p_' || to_char(m, 'YYYY_MM'), m, (m + interval '1 month'));
-END \$do\$;
+END $do$;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ci/journey.sh` around lines 3316 - 3334, Update the SQL heredoc in the qf
block to use a quoted EOSQL delimiter, matching the sibling story blocks. Remove
the manual backslash escapes from the PL/pgSQL dollar-quote delimiters so the
SQL remains unchanged while avoiding shell expansion.

2775-2821: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

ret_days computation is duplicated verbatim across 6 new stories.

local ret_days=$(( ( $(date -u +%s) - $(date -u -d "$(date -u +%Y-%m-01) -1 month" +%s) ) / 86400 )) is repeated identically here and at lines 2849, 2951, 3058, 3121, and 3315. Consider extracting a shared helper (e.g. retention_days_since_last_month() in ci/lib.sh) so the date-arithmetic logic has one source of truth.

♻️ Suggested helper
+# ci/lib.sh
+retention_days_since_last_month() {
+    echo $(( ( $(date -u +%s) - $(date -u -d "$(date -u +%Y-%m-01) -1 month" +%s) ) / 86400 ))
+}
-    local ret_days=$(( ( $(date -u +%s) - $(date -u -d "$(date -u +%Y-%m-01) -1 month" +%s) ) / 86400 ))
+    local ret_days; ret_days=$(retention_days_since_last_month)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ci/journey.sh` around lines 2775 - 2821, Extract the duplicated ret_days date
arithmetic into a shared retention_days_since_last_month helper in ci/lib.sh,
then replace the local calculations in story_partition_col_timestamp and the
other five stories with calls to that helper. Preserve the current UTC-based
result and days-since-start-of-last-month behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ci/journey.sh`:
- Around line 2922-2932: Update the typed_ext table definition’s col_oid column
from bigint to PostgreSQL oid, and remove the explicit bigint casts in both
INSERT statements so values are inserted as oid. Keep the TC-099 assertions and
surrounding typed-column coverage unchanged, ensuring the archiver/export path
exercises oid-to-bigint mapping.
- Around line 3345-3358: Update the TC-138 cleanup sequence to drop
public.sa_items as a view before dropping the underlying table, following the
existing cleanup pattern. Add the view drop before the existing DROP TABLE
statement, preserving the current cleanup order for coldfront metadata and sc2
schema removal.

In `@docs/animated_diagram.html`:
- Around line 912-944: Add a runToken generation counter near the animation
state and increment it in resetAnimationState before clearing visual state;
update animatePacket and delayStep to capture the current token and abort every
requestAnimationFrame, timeout, and continuation when it no longer matches.
Ensure self-restarting flows such as runTieredSelect use resetAnimationState to
invalidate prior chains, including concurrent fan-out animatePacket calls.
- Around line 1292-1298: Update resetAnimationState to restore watermark-text to
its initial value along with the existing partition labels and colors. Ensure
each animation loop starts with the original watermark and Phase 1 state, rather
than retaining the Phase 5 value of 2026-04-01.
- Around line 964-973: Update the animation timing logic in step so pausing
preserves accumulated packet progress and does not reset start or continuously
re-schedule requestAnimationFrame. Track the pause duration and shift start
forward when playback resumes, allowing progress to continue from its prior
position. Use an explicit start === null check so a timestamp of 0 remains
valid.
- Around line 829-830: Update the archive-button state handling around archBtn
to set its disabled property instead of relying on pointerEvents = 'none',
including the corresponding tiered-branch handling. Preserve the visual opacity
change while ensuring keyboard activation is blocked whenever the button is
unavailable.

---

Nitpick comments:
In `@ci/journey.sh`:
- Around line 3180-3189: Align the TC-113 story header comment with the behavior
described by step() in story_unlogged_rejected: state that registration is
accepted and rejection occurs at archive time. Do not change the implementation
or its intentionally lenient stage handling.
- Around line 2719-2743: Replace the interpolated bash -c TCP probe in
story_seaweedfs_restart with a direct subshell redirection to /dev/tcp using
SW_IP, avoiding re-parsing the address as shell code. Preserve the existing
retry counter, timeout, failure message, and post-readiness delay.
- Around line 3316-3334: Update the SQL heredoc in the qf block to use a quoted
EOSQL delimiter, matching the sibling story blocks. Remove the manual backslash
escapes from the PL/pgSQL dollar-quote delimiters so the SQL remains unchanged
while avoiding shell expansion.
- Around line 2775-2821: Extract the duplicated ret_days date arithmetic into a
shared retention_days_since_last_month helper in ci/lib.sh, then replace the
local calculations in story_partition_col_timestamp and the other five stories
with calls to that helper. Preserve the current UTC-based result and
days-since-start-of-last-month behavior.

In `@docs/animated_diagram.html`:
- Around line 752-753: Remove the unused currentStepIndex state declaration and
its assignment in runAction, unless step tracking is intentionally required; do
not alter the surrounding activeTimeline flow.
- Around line 868-872: Update togglePlay so the play-pause button exposes a
meaningful accessible label that reflects its current state, such as “Pause”
while playing and “Play” while paused, alongside the existing glyph and console
logging behavior.
- Around line 553-560: Give the range input in the animation-controls block an
accessible programmatic name by associating it with a visible label or adding an
appropriate accessible naming attribute. Preserve the existing slider behavior
and “Slower”/“Faster” visual guidance.
- Around line 633-646: The node groups node-client and node-hook are only
tooltip-accessible by mouse. Make each group keyboard-focusable with
tabindex="0", add matching onfocus and onblur handlers that invoke showTooltip
and hideTooltip, and ensure tooltip positioning falls back to the focused node’s
getBoundingClientRect() when no cursor coordinates are available; apply the same
accessibility behavior to every node group in the diagram.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0417b260-e081-44fb-8832-28ab1241522e

📥 Commits

Reviewing files that changed from the base of the PR and between 99e9c2e and dc7d1eb.

📒 Files selected for processing (2)
  • ci/journey.sh
  • docs/animated_diagram.html

Comment thread ci/journey.sh
Comment thread ci/journey.sh Outdated
Comment thread docs/animated_diagram.html Outdated
Comment thread docs/animated_diagram.html Outdated
Comment thread docs/animated_diagram.html Outdated
Comment thread docs/animated_diagram.html Outdated
@vyruss

vyruss commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

@coderabbitai I suspect the following may be true:

  • TC-043 never probes Parquet
  • TC-058 passes when it doesn't run
  • TC-059 leaves wh_bad_$$ behind on the unexpected-success path
  • TC-062 comment may be overstatement as SeaweedFS /data has no volume in docker-compose.matrix.yml (only read-only config mounts), so this does not prove on-disk durability
  • TC-099 has no oid column. col_oid bigint is a plain bigint round-trip. In journey we already assert oid is rejected at provisioning
  • TC-107 cannot fail
  • TC-109 "absent from archiver log": but does the archiver ever output table names?
  • TC-113 second half is dead code
  • TC-114 does not actually create a temp table
  • TC-138 is a false pass: nothing is archived, the premise is never asserted. its cleanup uses DROP TABLE on a view
  • TC-070, TC-113, TC-115, TC-116 run the shared /tmp/journey-archiver.yaml over every registered table, and the greps (not supported, unrecognized, parse.*bound) can match an unrelated table's failure. Use a per-story YAML like TC-107/109?
  • ret_days=$(( ... )) may need a DRY helper

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '=== journey script outline ==='
ast-grep outline ci/journey.sh --items all 2>/dev/null || true

printf '%s\n' '=== requested test-case locations and shared config references ==='
rg -n -C 5 \
  -e 'TC-(043|058|059|062|070|099|107|109|113|114|115|116|138)' \
  -e '/tmp/journey-archiver\.yaml' \
  -e 'ret_days=\$\(\(' \
  ci/journey.sh || true

printf '%s\n' '=== compose files and SeaweedFS volume configuration ==='
fd -a -t f 'docker-compose.matrix.yml|compose.*matrix.*\.ya?ml|.*matrix.*\.ya?ml' . -x sh -c '
  echo "--- $1"
  rg -n -C 8 "seaweed|volumes:|/data" "$1" || true
' sh {} \;

printf '%s\n' '=== archiver logging around table-name output ==='
rg -n -i -C 4 \
  -e 'log\.(Info|Debug|Error|Warn)|slog\.(Info|Debug|Error|Warn)|logger\.' \
  -e 'table.*name|table_name|TableName' \
  -g '*.go' . || true

Length of output: 115354


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '=== TC-107 through TC-116 implementations ==='
sed -n '3028,3302p' ci/journey.sh

printf '%s\n' '=== TC-138 implementation ==='
sed -n '3305,3360p' ci/journey.sh

printf '%s\n' '=== archiver registration loading and run loop ==='
rg -n -C 12 -e 'LoadTables\(' -e 'runCycle\(' -e 'for .*range .*tables' cmd/archiver

printf '%s\n' '=== partitioner/archiver command ownership and hot period validation ==='
rg -n -C 8 -e 'os\.Args|os\.Executable|Owner|PartitionOnly|Tiered|hot-period' \
  cmd/partitioner cmd/archiver internal/partcfg 2>/dev/null || true

printf '%s\n' '=== PostgreSQL oid mapping and rejection coverage ==='
rg -n -C 6 -e '"oid"|oid\b|pgFormatTypeToDuckDB' cmd/archiver ci/journey.sh

Length of output: 94216


@vyruss Confirmed—with two qualifications:

TC Assessment
043 Not quite: it does directly probe Parquet at ci/journey.sh Lines 2663–2665 via iceberg_metadata(... WHERE file_format='PARQUET'). However, its fallback at Lines 2667–2669 only proves rows are readable, not that the metadata query works or reports Parquet. The fallback should be labeled as a degraded cold-read check, or the test should fail when the metadata facility is expected to exist.
058 Valid false pass. pg_dump is captured in a command substitution without checking its exit status. An execution failure produces an empty dump, no secret matches, and a pass.
059 Valid. The unexpected-success branch reports failure but does not delete wh_bad_$$, leaving the warehouse behind.
062 Valid overstatement. docker-compose.matrix.yml runs SeaweedFS with -dir=/data, but only mounts read-only configuration files. Restarting the same container verifies in-container restart survival, not host-backed/on-disk durability across container replacement.
099 Valid. col_oid is declared as bigint and populated with 12345::bigint; this is a bigint round-trip. Real PostgreSQL oid is intentionally rejected in both the journey provisioning check and pgFormatTypeToDuckDB. TC-099 should be renamed to reflect the supported bigint workaround, or removed as an oid test.
107 Valid, and stronger than stated. It registers both tables without --hot-period, making them partition-only. The archiver loads only enabled rows where hot_period IS NOT NULL, so neither TC-107 table is selected. The test then accepts both an exit-zero run and an orders table that remains non-view, so it cannot establish failure isolation. Any nonzero result could only come from an unrelated registered tiered table.
109 The concern about logging is not valid literally: the archiver does log source table names, including [%s] starting archive cycle and export messages such as [%s] exporting .... Since logs has a cold candidate, its name being absent is useful evidence it was not processed. Still, the test should additionally assert the disabled table remains a partitioned table and has no watermark/tiered-view row; that is stronger than a log assertion alone.
113 Valid in substance. The second archive invocation is reachable syntactically, but if registration rejects the UNLOGGED table, it cannot test that table’s archive-time rejection. It instead runs every other enabled tiered registration and may pass on an unrelated failure. Also, neither the registration-rejection branch nor the successful-registration/archive branch is required to produce a definitive pass/fail outcome.
114 Valid. It never creates a temporary table in a separate session. It only registers a nonexistent relation, which tests nonexistent-table handling—not TEMP visibility across connections.
138 Valid false pass. It registers both tables with retention only, so both are partition-only and excluded from the archiver. The subsequent reads see the original PostgreSQL rows, while the cleanup uses DROP TABLE against relations that would be views only if archival occurred. It needs tiered registrations (--hot-period) plus pre-archive assertions that both source partitions exist and post-archive assertions that both relations became views / have distinct Iceberg references.
070 / 113 / 115 / 116 Valid contamination concern. Their archiver invocations resolve all enabled tiered rows from shared coldfront.partition_config; broad error greps can match another table’s failure. A per-story YAML alone is insufficient: TC-107 and TC-109 demonstrate that the YAML supplies connection/storage configuration, while the actual table set still comes from the registry. Isolation requires disabling/removing other tiered rows for the run (and restoring them), or adding an explicit table-selection option to the archiver. Each test should also assert its own row was registered and bind the expected failure to that table.
ret_days Agreed. The same UTC month-boundary arithmetic is repeated many times. A small helper such as hot_period_to_previous_month_start_days() would make the cutoff invariant explicit and reduce copy/paste drift.

The most consequential fixes are TC-058, TC-107, TC-114, TC-138, and registry isolation for the negative archive tests.

@vyruss

vyruss commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Fixing some of the tests which were passing without exercising their premise:

  • TC-043: resolve metadata-location from Lakekeeper, then iceberg_metadata() on that path. It takes a filesystem path, not a catalog ref, so the story always took its fallback.
  • TC-058: assert the dump is real (CREATE EXTENSION present) before concluding nothing leaked; grep -qF for all secrets.
  • TC-059: delete the warehouse if Lakekeeper unexpectedly accepts it.
  • TC-062: comment scoped to container restart, /data has no volume.
  • TC-066, TC-067, TC-070, TC-115, TC-116: scope each archiver run to its own registry row via a new archive_only() helper. Pointing the archiver at a per-story YAML does not limit which tables it touches: it reads its work list from coldfront.partition_config, so an unrelated table's failure could be mistaken for the one under test.
  • TC-099: dropped. col_oid was declared bigint; renamed col_oid_workaround. Real oid is rejected at provisioning and story_types covers that.
  • TC-107: add --hot-period, without which the table is partition-only and the archiver never loads it. Reframed to fail-fast: prepareAndRunTable calls log.Fatalf on the first table error and LoadTables orders by name, so logs aborts the run before orders is reached.
  • TC-109: add relkind plus no-watermark and no-registry assertions.
  • TC-110: own log file, journey-idem.log is already taken.
  • TC-113: drop the dead second archiver pass, assert the register rejection.
  • TC-114: create a real TEMP table and prove it visible in its own session first.
  • TC-138: add --hot-period for the same reason as TC-107, then assert both tables become views with distinct Iceberg names; cleanup drops the view and _sa_items.

hot_days() is a new helper replacing twelve copies of the cutoff arithmetic.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
ci/journey.sh (1)

2942-2942: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Rejection greps run against a log that already contains register output.

In all three stories the register step writes its output to the same file (>), and archive_only appends the archive run (>>). The subsequent grep -qi "…unsupported\|LIST\|HASH\|parse.*bound…" therefore can be satisfied by text produced before the archive ran, so the "rejected at archive time" assertion isn't strictly attributable to the archiver run. Using a separate log for the archive pass makes the attribution exact.

♻️ Example for TC-070
-    if archive_only "schema_name='public' AND table_name='tc070_textpart'" /tmp/journey-archiver.yaml /tmp/journey-textpart.log; then
+    : > /tmp/journey-textpart-arch.log
+    if archive_only "schema_name='public' AND table_name='tc070_textpart'" /tmp/journey-archiver.yaml /tmp/journey-textpart-arch.log; then
         fail "TC-070: archiver should have rejected text partition column"
     else
-        if grep -qi "cannot parse partition bound\|unsupported partition\|unsupported.*column\|not supported\|unrecognized\|parse.*bound" /tmp/journey-textpart.log; then
+        if grep -qi "cannot parse partition bound\|unsupported partition\|unsupported.*column\|not supported\|unrecognized\|parse.*bound" /tmp/journey-textpart-arch.log; then

Also applies to: 3335-3335, 3369-3369

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ci/journey.sh` at line 2942, Use a dedicated log file for each archive_only
invocation in the affected TC-070, TC-071, and TC-072 stories instead of the
register output log. Update the archive_only calls and their rejection greps so
each assertion reads only the archive pass output, preserving the existing
register logging and rejection patterns.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@ci/journey.sh`:
- Line 2942: Use a dedicated log file for each archive_only invocation in the
affected TC-070, TC-071, and TC-072 stories instead of the register output log.
Update the archive_only calls and their rejection greps so each assertion reads
only the archive pass output, preserving the existing register logging and
rejection patterns.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 96678383-3992-49b4-bfaa-4c224363db0c

📥 Commits

Reviewing files that changed from the base of the PR and between dc7d1eb and 390a073.

📒 Files selected for processing (1)
  • ci/journey.sh

@vyruss
vyruss force-pushed the test/automate-functional-tcs branch from 390a073 to b5a1b90 Compare July 28, 2026 22:53
@vyruss
vyruss merged commit 81c4c2c into main Jul 28, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants