Skip to content

test(amber): cover exportOperatorsAsZip and the remaining ResultExportService entry points - #7816

Open
eugenegujing wants to merge 2 commits into
apache:mainfrom
eugenegujing:test/result-export-zip-spec
Open

test(amber): cover exportOperatorsAsZip and the remaining ResultExportService entry points#7816
eugenegujing wants to merge 2 commits into
apache:mainfrom
eugenegujing:test/result-export-zip-spec

Conversation

@eugenegujing

@eugenegujing eugenegujing commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

What changes were proposed in this PR?

This PR extends amber/src/test/scala/org/apache/texera/web/service/ResultExportServiceSpec.scala (40 → 60 tests) to cover the three ResultExportService methods that previously had zero test references anywhere in the repository — exportOperatorsAsZip, exportSingleOperatorToDataset and getOperatorDocument — together with the edge cases of the export paths that reach them.

  • exportOperatorsAsZip: throws WebApplicationException when the workflow never ran (where the sibling exportOperatorResultAsStream returns (null, None) for the same condition); names the archive <workflowName>-<yyyy-MM-dd_HH-mm-ss>.zip; dispatches each entry through the per-format writer on that operator's own outputType, with an unrecognised type falling back to CSV; routes every entry through NonClosingOutputStream so one entry's writer closing its stream cannot close the shared ZipOutputStream (asserted by a later entry surviving an earlier writer's close — the wrapper was already unit-tested in isolation, but nothing checked that the ZIP path uses it); and substitutes a <id>-empty.txt placeholder instead of aborting the archive, covered for both halves of the guard — an operator with no stored result URI, and an operator whose stored result table exists but holds zero rows.
  • exportSingleOperatorToDataset (driven through exportToDataset): uploads each operator's rows to the file service in that operator's own format with the exact bodies asserted against a stub upload server, turns a thrown per-operator failure into an error entry instead of aborting the batch, reports a stored-but-empty result as having nothing to export, and pins the partial-success policy as characterization — when some operators export and some fail, the response is success carrying only the success lines.
  • getOperatorDocument: returns null when the operator stored no result URI, opens the stored result document with its count and contents read back, and refuses a result stored in a per-user warehouse while the feature is off (WarehouseUnavailableException via the WarehouseReadGuard from [BYO-S3] Feature flag (storage.warehouse.enabled, default off) #6930).
  • Edge cases along these paths: every row is written on both sides of the CSV chunk-buffer boundary (CHUNK_SIZE 10, exercised one-under, exactly-one and one-over); CSV values containing a comma, a double quote, a newline and non-ASCII text round-trip through the streamed export; streamCellData accepts the maximum row and column index and rejects the out-of-range ones with their exact reasons, while negative indexes are pinned as characterization because the >= guards let them through to an internal reader error and an array-index error; a result stored under an older execution is not exported once a newer execution exists, and the newer execution's rows win when both stored results; and requesting the same operator twice aborts the archive mid-stream with a duplicate-entry ZipException, pinned as characterization since the client has already received its 200 by then.

Tests that need actual rows open real Iceberg result tables, following the arrangement ExecutionResultServiceSpec already uses in amber unit tests. The section banner and class scaladoc described the request-level tests as stopping short of opening a result document, so they are updated to describe what these tests now do. No production code is changed.

Any related issues, documentation, discussions?

Closes #7814

How was this PR tested?

All changes are new or extended unit tests in ResultExportServiceSpec; run them with STORAGE_ICEBERG_CATALOG_TYPE=postgres sbt "WorkflowExecutionService/testOnly org.apache.texera.web.service.ResultExportServiceSpec" — 60 succeeded, 0 failed, and the suite was verified idempotent by running twice back-to-back against the same catalog database. Key assertions were mutation-checked by hand-editing production code and confirming that exactly the intended tests fail: replacing the NonClosingOutputStream wrapper with the raw stream, making the wrapper's close() close the underlying stream, skipping the empty-operator placeholder branch, dropping the zero-row half of both placeholder guards, forcing the ZIP dispatch to CSV, dropping the timestamp from the archive name, returning (null, None) instead of throwing when there is no execution, breaking the result-document lookup, removing the WarehouseReadGuard check, appending the dropped error lines to a partial-success response, cutting the CSV chunk loop to a single chunk, and resolving the oldest execution instead of the latest. Every mutation was reverted byte-exact afterwards, and scalafmtCheck passes.

Was this PR authored or co-authored using generative AI tooling?

Generated-by: Claude Code (Claude Fable 5, Claude Opus 5)

…tService entry points

Extend ResultExportServiceSpec from 40 to 60 tests: exportOperatorsAsZip's no-execution throw, archive naming, per-operator format dispatch with unknown-type CSV fallback, the NonClosingOutputStream multi-entry contract, and the empty-operator placeholder for both a missing result URI and a stored-but-zero-row table; exportSingleOperatorToDataset's per-format upload and partial-success policy; getOperatorDocument's null, real-document and WarehouseReadGuard-refusal branches; and the surrounding edge cases — CSV chunk-boundary and special-character round-trips, streamCellData's index limits, latest-execution resolution, and the duplicate-operator archive abort. Result-bearing tests store real Iceberg tables via the arrangement ExecutionResultServiceSpec already uses, which also retires the spec's stale "needs a live Iceberg catalog" banner.
@github-actions

Copy link
Copy Markdown
Contributor

Automated Reviewer Suggestions

Based on the git blame history of the changed files, we recommend the following reviewers:

  • Contributors with relevant context: @aglinxinyuan
    You can notify them by mentioning @aglinxinyuan in a comment.

@github-actions

github-actions Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

⚠️ Benchmark changes need a look

🟢 4 better · 🔴 1 worse · ⚪ 10 noise (<±5%) · 0 without baseline

Compared against main 2edbdf9 benchmarked on this same runner, so the delta is largely free of cross-runner hardware noise. The "7d avg" column still reflects the gh-pages dashboard. Treat <±5% as noise unless repeated.

Dashboard · Run

config throughput MB/s latency max Δ latest / 7d
🔴 bs=10 sw=10 sl=64 381 0.233 24,826/34,260/34,260 us 🟢 -31.4% / 🔴 +128.5%
🟢 bs=100 sw=10 sl=64 804 0.491 125,218/137,667/137,667 us 🟢 -19.7% / 🔴 +29.8%
bs=1000 sw=10 sl=64 925 0.565 1,076,062/1,146,346/1,146,346 us ⚪ within ±5% / 🔴 +13.5%
Baseline details

Latest main 2edbdf9 from same runner

config metric PR latest main 7d avg Δ latest Δ 7d
bs=10 sw=10 sl=64 throughput 381 tuples/sec 388 tuples/sec 780.31 tuples/sec -1.8% -51.2%
bs=10 sw=10 sl=64 MB/s 0.233 MB/s 0.237 MB/s 0.476 MB/s -1.7% -51.1%
bs=10 sw=10 sl=64 p50 24,826 us 22,224 us 12,590 us +11.7% +97.2%
bs=10 sw=10 sl=64 p95 34,260 us 49,960 us 14,995 us -31.4% +128.5%
bs=10 sw=10 sl=64 p99 34,260 us 49,960 us 19,141 us -31.4% +79.0%
bs=100 sw=10 sl=64 throughput 804 tuples/sec 805 tuples/sec 1,006 tuples/sec -0.1% -20.1%
bs=100 sw=10 sl=64 MB/s 0.491 MB/s 0.491 MB/s 0.614 MB/s 0.0% -20.0%
bs=100 sw=10 sl=64 p50 125,218 us 119,979 us 99,387 us +4.4% +26.0%
bs=100 sw=10 sl=64 p95 137,667 us 171,545 us 106,056 us -19.7% +29.8%
bs=100 sw=10 sl=64 p99 137,667 us 171,545 us 113,689 us -19.7% +21.1%
bs=1000 sw=10 sl=64 throughput 925 tuples/sec 912 tuples/sec 1,043 tuples/sec +1.4% -11.3%
bs=1000 sw=10 sl=64 MB/s 0.565 MB/s 0.557 MB/s 0.637 MB/s +1.4% -11.3%
bs=1000 sw=10 sl=64 p50 1,076,062 us 1,093,310 us 965,215 us -1.6% +11.5%
bs=1000 sw=10 sl=64 p95 1,146,346 us 1,138,790 us 1,009,610 us +0.7% +13.5%
bs=1000 sw=10 sl=64 p99 1,146,346 us 1,138,790 us 1,039,108 us +0.7% +10.3%
Raw CSV
config_idx,batch_size,schema_width,string_len,num_batches,total_ms,total_tuples,total_bytes,tuples_per_sec,mb_per_sec,lat_p50_us,lat_p95_us,lat_p99_us
0,10,10,64,20,524.55,200,128000,381,0.233,24826.10,34259.61,34259.61
1,100,10,64,20,2486.62,2000,1280000,804,0.491,125218.43,137667.15,137667.15
2,1000,10,64,20,21618.79,20000,12800000,925,0.565,1076061.97,1146346.35,1146346.35

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.37%. Comparing base (2edbdf9) to head (83e646c).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@             Coverage Diff              @@
##               main    #7816      +/-   ##
============================================
- Coverage     91.50%   91.37%   -0.14%     
+ Complexity     4501     4475      -26     
============================================
  Files          1177     1169       -8     
  Lines         47489    47148     -341     
  Branches       5324     5288      -36     
============================================
- Hits          43457    43080     -377     
- Misses         2366     2405      +39     
+ Partials       1666     1663       -3     
Flag Coverage Δ *Carryforward flag
access-control-service 81.00% <ø> (ø) Carriedforward from 9c5aecc
agent-service 98.62% <ø> (ø) Carriedforward from 9c5aecc
amber 88.13% <ø> (+0.09%) ⬆️
computing-unit-managing-service 73.67% <ø> (ø) Carriedforward from 9c5aecc
config-service 86.73% <ø> (ø) Carriedforward from 9c5aecc
file-service 65.41% <ø> (-10.34%) ⬇️ Carriedforward from 9c5aecc
frontend 92.88% <ø> (-0.36%) ⬇️ Carriedforward from 9c5aecc
notebook-migration-service 78.86% <ø> (-0.28%) ⬇️ Carriedforward from 9c5aecc
pyamber 97.56% <ø> (-0.01%) ⬇️ Carriedforward from 9c5aecc
workflow-compiling-service 77.19% <ø> (ø) Carriedforward from 9c5aecc

*This pull request uses carry forward flags. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

extend ResultExportServiceSpec to cover exportOperatorsAsZip and the two remaining export entry points

3 participants